Android app crashes after switching from .lib to .so - android

I am using a number of static pre-built static libraries in my native android application and everything works fine. Now I want to switch one of my static libraries to be .so. I was successfully able to build .so library by replacing BUILD_STATIC_LIBRARY with BUILD_SHARED_LIBRARY in its android.mk and adding required dependencies.
I was also able to build my application by replacing corresponding PREBUILT_STATIC_LIBRARY with PREBUILT_SHARED_LIBRARY in its android.mk. The resulting application now fails to start. I cannot even get to point where debugger attaches to the application.
Besides that what I do not understand is how the build system knows that the function should be imported from the library. My so library should export one function, but I did not declare it as dllexport/import or something. Still there are no unresolved symbols in my application (when I remove my prebuilt library from the list, the unresolved symbol appears as expected).
The other question is that I see there are two .so files generated. One big file in obj/local/$(TARGET_ARCH_ABI) folder and another small one in libs/$(TARGET_ARCH_ABI). When declaring my prebuilt library I reference the second one in libs folder.
I did try to search stackoverflow for answers and found quite a few related posts:
loading library (.so file) in android
NDK - How to use a generated .so library in another project
How to use .so file in Android code to use the native methods
How to use libffmpeg.so in Android project?
but I do not see how these posts related to my problem since I can successfully build and even link my application.

You need to load the libraries in reverse dependency order in the java code. You previously probably have something like this:
System.loadLibrary("mylib");
Now if your prebuilt library (that was previously a static library, now a shared library) is named dependencylib, you need to change the code for loading the libraries into this:
System.loadLibrary("dependencylib");
System.loadLibrary("mylib");
As for your question how the linker can figure it out; when linking libmylib.so, it looks for all undefined symbols in all the other libraries you specified (i.e. in libdependencylib.so, and in libc.so and other system libraries). As long as all undefined symbols are found somewhere, the linker is ok. Then at runtime, when libmylib.so is loaded, it does the same routine again; all undefined symbols are looked up in the list of symbols loaded in the current process. On linux, you normally don't need to manually mark symbols as dllexport as you do on windows - all non-static symbols are exported by default.

There may be two reasons why the app fails to start after the change of STATIC -> SHARED.
The prebuilt library is not installed. With your device connected, run adb ls -l /data/your.package.name/lib/. Do you see the library there?
The prebuilt library is not loaded. In your main Java class, try
static {
System.loadLibrary("prebuiltname");
System.loadLibrary("yourlib");
}
This is a static constructor, the safest place to load JNI library.

If you are on linux you will see exported symbols using nm -D. example nm -D libzip.so:
...
0000000000009dc0 T zip_unchange
0000000000009dd0 T zip_unchange_all
0000000000009e30 T zip_unchange_archive
0000000000009e60 T _zip_unchange_data
If you want to control visibility of your functions use __attribute__ ((visibility ("default"))) and command line -fvisibility=hidden. More information here.

Now I want to switch one of my static libraries to be .so. I was successfully able to build .so library by replacing BUILD_STATIC_LIBRARY with BUILD_SHARED_LIBRARY in its android.mk and adding required dependencies.
I don't think you can do it if its a C++ library. From <doc>/CPLUSPLUS-SUPPORT.html:
Please keep in mind that the static library variant of a given C++
runtime SHALL ONLY BE LINKED INTO A SINGLE BINARY for optimal
conditions.
What this means is that if your project consists of a
single shared library, you can link against, e.g., stlport_static, and
everything will work correctly.
On the other hand, if you have two
shared libraries in your project (e.g. libfoo.so and libbar.so) which
both link against the same static runtime, each one of them will
include a copy of the runtime's code in its final binary image. This
is problematic because certain global variables used/provided
internally by the runtime are duplicated.
This is likely to result in code that doesn't work correctly, for example:
* memory allocated in one library, and freed in the other would leak
or even corrupt the heap.
* exceptions raised in libfoo.so cannot be caught in libbar.so (and may
simply crash the program).
* the buffering of cout not working properly
This problem also happens if you want to link an executable and a shared
library to the same static library.
In other words, if your project requires several shared library modules,
then use the shared library variant of your C++ runtime.
From above, it means everything needs to link against the same C++ standard runtime shared object.

Related

How to properly setup dynamic library loading with header file?

The title was tough to get right, so let me explain my situation:
Another team develops a library. They ship a header file and a *.so file. The header file is available to us, and we can include it in our own code and use it if we wish. The *.so, however, is shipped with the platform we run on. We do not have access to this *.so at build time for our software. Because of this, we can't really use the header file either, since the linker will expect the *.so to be available at some point.
Right now what I do is create a wrapper class that loads the *.so file at runtime, then uses dlsym() to find functions by name, and I map them to function pointers.
Is this the only option? Is there a way I can use the header file but tell the linker to not resolve the symbols at build time, but instead try to resolve them at runtime after we have a chance to load the *.so file?
Note the real platform here is Android (via NDK), but hoping general linux advice will work as well in this case since we have POSIX APIs available.
You have a few options, in order of preference:
Get the libraries from the maintainer. Providing the header but not the library (at least a stub library like we do for libraries in the NDK) just won't work.
Build your own stub library. It's pretty straightforward if you have a list of symbols to expose. Put int foo; void bar() {} in a C file for all the variables and functions you need to expose and build it as a shared lib. If you have the list of symbols in a version script, you might be able to use Android's gen_stub_libs.py to do it for you.
Mark all the symbols with __attribute__((weak)) in the header file. The linker won't complain that they are missing. If they're missing at runtime, the library will still load but each function's address will be nullptr. Not really what you want in most cases because if your definition of the library is wrong, you turn build time failures into runtime failures, but in some cases this can be handy because it's easier to check for function availability with if (foo) { foo(); } then to do similar with dlsym.
Add -Wl,--allow-shlib-undefined to your ldflags. This is even worse than 3 because it affects all the libraries you link, but it wouldn't require you to meddle with the header.
On Windows this is solved by requiring export library (.lib) to be present for linker instead of real dynamic library (.dll). I think you can try making something similar, that is making a fake .so containing stubs of all the methods exported from real .so and linking against it. This hopefully will make linker happy and at the same time at runtime application will load real .so.

How to link against a shared library without inclusion in final package?

I have been working with a project that needs to link against two shared libraries from other applications, without actually including them in the final package. I was using Android Studio with a common way of executing an external ndk-build but I am now using the experimental gradle NDK support.
From what I understand from the information here, using the jniLibs source set will package the binary with the final application, which is not what I want. I would like to link against the libraries during compile time, and expect that my own module is loaded in an environment where they are available.
My old workaround was to add the line: TARGET_NO_UNDEFINED_LDFLAGS := within the Android.mk, but I'm not aware of any way to something equivalent with the new NDK support.
Currently, I am including the jni directory which contains the libraries alongside my source by adding -L"<directory>" to ldFlags, and linking against them as I would with a system library, as below (currently, I am only building for ARMv7):
android.ndk {
moduleName = "ropecraftpe"
ldLibs.addAll(['log', 'name of one library', 'name of other library'])
ldFlags.add('-L"' + file('src/main/jni').absolutePath + '"')
cppFlags.add('-std=c++11')
stl = 'gnustl_shared'
abiFilters.addAll(['armeabi-v7a'])
}
This works for the most part - oddly enough, the linker does not complain about calls to static functions or globals, but does complain when attempting to use a constructor defined in one of the libraries: Error:(12) undefined reference to 'ClassName::ClassName(std::string const&, etc.)'. This class is defined in a header file included from my own C++ code, and the constructor is definitely present in the linked .so.
How does one go about linking this project successfully?
I have made a workaround; my solution was to add the libraries that I wished to link against to the NDK's system library directory.
This is located under ANDROID_NDK/platforms/android-XX/arch-XX/usr/lib/. This appears to work fine, as I wanted the libraries to be treated in the same way as system libraries (not included as prebuilts, but still linked against).
As an addition, one can place the header files under the include directory there.

Make a library that is statically linked

So , I have installed Ubuntu(but still use the Android kernel) on my Android phone with the intention of using it to compile native code for the device using the glibc.
I made a library, which I plan to use it in an app which I want to make, using JNI, but I am using the math library. My question is:
Is there a way to include these libraries into the library that I
created so that my phone can use the glibc library instead of the
bionic(which is what the NDK uses) library?
NOTE: I have tried making a test program that uses the library and statically links to make sure that the compiled code would work on the android OS and not just Ubuntu, and I came to the conclusion that it does :) So any answer pertaining to my question would be a great help.
You can use ar to extract the original .o files from any .a files:
ar x libm.a
You can then select whichever .o files you like and link them into your own code.
.a library files can be viewed as tar files with extra symbol-index features (although I don't know how similar the internals are).
WARNING: in general, you can only use .o files from static libraries in your main application. If you try to link them into a shared library (.so file) you may be out of luck. The .o file needs to have been created with -fPIC for that to work, and this is often not the case for static libraries.

How can I separate JNI part from the Android app?

I am writing an Android application. I am implementing some of the app in C++ using JNI. Is there a way to actually separate completely the JNI (C++) code from the Java Android code? Like creating a JNI project or something ? Because my C++ code will become a little library that I will use in another app. I tried to create a C++ project but I can't compile with ndk-build.
In actuality, the tie-in between the Java and native code is fairly loose, in that it is done by the names of the methods at runtime.
The NDK is just a special environment and libraries for a C compiler. A suitable dynamic library file must be produced, but this can be done using the ndk script, using an ndk generated "stand alone tool chain" or even done before (or after, see later) the java project build, done on another machine, etc.
Normally the .so dynamic library gets copied into the appropriate place in the application project tree such that it will end up packaged in the .apk and installed on the device where it can be automatically found by the System.loadLibrary() method. But you could just insert it into the otherwise finished .apk (which is a zip file with special alignment and jarsigner signatures). But even the .pak is not actually not the only way to deliver it to the device (though it is the only recommended way)- a library can also be stored in a place such as the app's private folder and loaded using System.load() which takes a full pathname instead of a library name.
hotverspicy does have a point that the java code needs a native method "declaration" for what is implemented in the jni library, and that this needs to match the actual package name as encoded in the name of the native function implementation. However, that package name does not have to be the same as the rest of the java code - it could be something generic for the re-usable C/C++ library, which would require only one brief matching java class file in the matching java package name.
But in addition to Neevek's idea of using one native lib to interface to another, it is also likely possible to use an object factory mechanism to hook up arbitrary native functions at runtime, given just one association set up at compile time - see the relevant answer to C/C++ Reflection and JNI - A method for invoking native code which hasn't been written yet
If you use JNI in your C++ code, then it's bound to Android, and it must be an Android project with properly defined Android.mk, Application.mk(optional).
If you don't use JNI API in your code, say you want to create a generic library, you can just write your C++ code, compile it, test it as usual, no ndk-build is needed. When you finish coding with the library, build the code as a static library, and when you want to use this static library in your Android project, write some JNI wrappers around functionalities in the static library that you want to use, link against the static library in your Android.mk, something like this:
include $(CLEAR_VARS)
LOCAL_MODULE := libgeneric
LOCAL_SRC_FILES := prebuilt/libgeneric.a
include $(PREBUILT_STATIC_LIBRARY)

Problem loading pre-built library via Android NDK

I am attempting to add a third-party library to my Android app. It utilizes a .jar file and a .so file. This is a pre-built .so file (i.e. not built specifically for the Android app) - which I know will provide me with plenty of problems down the road. I do NOT have access to the source files for the .jar or .so files!
I am attempting to dynamically load the library via a call to System.loadLibrary("foo");. Currently, when attempting to run the app, it crashes with the UnsatisfiedLinkError: Library foo not found. I have the .so file in both the libs/ and the libs/armeabi file in my project.
Am I chasing after a ghost here? I am trying to determine if what I'm after is even feasible. I have no native code that I'm referencing - all my function calls are to the .jar file that is, as I understand it, backed by the .so file. I have not run the Android.mk file as I'm not compiling anything - the .so file is already provided. I could really use some advice as to what direction to proceed from here.
It's possible that the base name given to System.loadLibrary() is expanding to a file (or path) name different than that of the actual prebuilt library. Logcat should show you exactly what it is trying to load. You could also use System.load() with a full path/file name instead of System.loadLibrary() - though you really should get it working with the later.
While I think it would generate a different error message, it's also possible that the .so is not android compatible - it must not only be for a compatible processor type and abi, but not depend on any dynamic libraries (such as a non-bionic libc) not installed on the device.

Categories

Resources