Symptoms
You are trying to load your native C/C++ library in an Android application and when at runtime your app calls the System.loadLibrary() function - for example:
static {
System.loadLibrary("mynativelib");
System.loadLibrary("mynativelib");
}
the application dies without core dumping, and the only message you see in LogCat is something like the following:
01-23 19:58:08.699: D/dalvikvm(4146): Trying to load lib /data/data/com.example.myapp/lib/libmynativelib.so 0x42341a50
01-23 19:58:08.709: I/ActivityManager(340): Process com.example.myapp (pid 4146) has died.
01-23 19:58:08.709: W/ActivityManager(340): Force removing ActivityRecord{211d37d0 com.example.myapp/.MyActivity}: app died, no saved state
01-23 19:58:08.719: D/Zygote(188): Process 4146 terminated by signal (11)
01-23 19:58:08.709: I/ActivityManager(340): Process com.example.myapp (pid 4146) has died.
01-23 19:58:08.709: W/ActivityManager(340): Force removing ActivityRecord{211d37d0 com.example.myapp/.MyActivity}: app died, no saved state
01-23 19:58:08.719: D/Zygote(188): Process 4146 terminated by signal (11)
Causes
You native library is probably trying to dynamically load another library it depends upon.Solution
Use the GCC readelf for your ABI to dump the dynamic section of your native library and find out which libraries it depends upon. For example if you are compiling for the x86 ABI:$ android-ndk-r8d/toolchains/x86-4.7/prebuilt/linux-x86/bin/i686-linux-android-readelf -d libmynativelib.so | grep NEEDED
0x00000001 (NEEDED) Shared library: [libgnustl_shared.so]
0x00000001 (NEEDED) Shared library: [libiconv.so]
0x00000001 (NEEDED) Shared library: [libdl.so]
0x00000001 (NEEDED) Shared library: [libstdc++.so]
0x00000001 (NEEDED) Shared library: [libm.so]
0x00000001 (NEEDED) Shared library: [libc.so]
In this example you only need to load libgnustl_shared.so and libiconv.so before your libmynativelib.so to resolve the dependencies and make the System.loadLibrary() function call happy (the other standard libraries are already preloaded for you by Android). In your static section you will then include the following lines:
static {
System.loadLibrary("gnustl_shared");
System.loadLibrary("iconv");
System.loadLibrary("mynativelib");
}
This should solve the problem.
The info you provided in the blog that was really unique I love it!!!
ReplyDeleteiPhone developer in Pakistan
Hi I'm trying to create a distributable Android library as a JAR file, that includes native code. Any tips for packaging a native library (.so file built with NDK) within a JAR?
ReplyDeleteHi,
Deletein our setup we have a bunch of native C++ libraries built with the NDK and a JNI wrapper library with the calls to these libraries' native methods (say lib projectjni.so).
What we usually do is take all the native libraries built with the NDK plus the libprojectjni.so library and zip them in a file (say "projectlibs.zip"). We then include this zip file inside the jar file.
A developer receiving your distribution jar file can then drop it in the lib project directory and access all the native calls via the JNI API. One of this API call - loadNativeLibraries() - must be called inside an application first, and it will unzip the projectlibs.zip file, install the libraries, and load them by calling the System.load() function on each unzipped native library.
Hope this helps.
Thank you, this is very helpful. By "install the libraries" do you mean that you unzipped them to a directory in internal storage, and if so, did you encounter any issues with inter-library dependencies? I've read elsewhere that if lib1.so depends on lib2.so, it will look in $LD_LIBRARY_PATH to find it (and thus fail to find it)
DeleteAndroid creates a sandbox for you app with a new user id so that all files have private permissions and no other application can mess up with your files. Android installs you app usually under /data/data/com... Here Android will install all the libs that your app depends on in the "lib" subdirectory.
DeleteBy installing the libraries I mean you need to unzip them inside any directory but lib (because lib is owned by root and the only way Android will install any library here is only when you call the System.loadlibrary() method.).
So for example you can unzip your native libs under /data/data/com../-libs. Then if you call the System.load() instead of loadlibrary() on each unzipped library, Android will let you load them without problem - provided you don't have a library with the same name as one of the system libraries.
Another problem you could have is to load your native libraries in a particular order. I mean if library A depends on B, you need to first load B and then A.
To solve this problem you can have an additional text file in your zip file containing the load order for you libraries. Then the loadNativeLibraries() method mentioned above, after unzipping all files could read the load-order text file and start loading your native libraries in the order listed in the file.
Sorry: the directory names mentioned above were mangled when published. I meant: /data/data/com... is /data/data/com.company.app, and /data/data/com../-libs is /data/data/com.company.app/appname-libs.
DeleteAlso to further clarify your last question, the secret is to call the System.load() with the absolute path to the native libraries. If you use just the library name, then Android will look for it by exploring the LD_LIBRARY_PATH.
You get the absolute path where to unzip your libs by calling the dataDir method in Java as follows:
String libDir = getPackageManager().getApplicationInfo(getPackageName(), 0).dataDir + File.separator + "appname-libs";
This comment has been removed by the author.
ReplyDelete