Should I rebuild all libs when I upgrade the NDK version? - android

There's many shared libs(*.so) in my android project. Some of them were built by others, I don't have the source code.
I'm using NDK r10e, and I want to upgrade the NDK version to r13b.
If I don't change the makefile, just build part of the shared libs with NDK-r13b, others built with NDK-r10e were not changed. Is there any problem with capability of the android program?
NDK-r10e use clang-3.5
NDK-r13b use clang-3.8
following configurations are the same:
APP_ABI := armeabi-v7a
APP_PLATFORM := android-19
APP_STL := gnustl_shared

It's generally a good idea, but isn't always required. We try to preserve compatibility across NDK versions since, yes, moving across a compatibility boundary is difficult when you don't have the source to your dependencies, but sometimes bugs can't be fixed without breaking compatibility.
It's generally a good idea because doing so will have the least surprises. We only ever test a version of the NDK against itself. It will also save you a lot of time trying to figure what went wrong when there are compatibility breaks.
A couple examples (by no means a complete list) of things that can go wrong:
The public API surface of the NDK has changed over time. The APIs still exist on the device so that legacy apps continue working, but sometimes APIs are removed from the NDK so that new apps don't use them (there are a handful of reasons this might happen). In these cases, an old library that uses a removed symbol won't be able to be linked against a new library/executable using an NDK that doesn't have those APIs (this actually depends on the behavior of the linker; it's always true for static libraries, I think it's only arm64 for shared libraries).
For upgrading from r10 in particular, there was an ABI break in libc++ (required to avoid nasty interactions with the system) that means that libraries built with r10 and libraries built with r11+ are not compatible. You're using gnustl, so that problem won't affect you, but it's worth mentioning for others that land here.

Related

Android NDK: Static or shared C++ runtime for 3rd-party Java library

I'm compiling a 3rd-party Java library for Android that uses JNI. I read the relevant pages on adding C++ support on developer.android but I'm still confused about a couple of issues regarding C++ STL runtime that I was hoping I could clear up here:
1- My library has no control over the app it will be embedded in, so I don't know if there will be other libraries that might use a static/shared STLs. If I use a static C++ runtime with ANDROID_STL=c++_static, is it safe, or should I have to worry about another library that could be using something like gnustl_static which might conflict with mine?
2- If I use a shared C++ runtime with ANDROID_STL=c++_shared, is it a guarantee that a specific element in the STL will use the libc++ runtime or could it be possible to use gnustl if it doesn't exist? For example, If I was using std::string with a shared c++ runtime (c++_shared) in an app that has another library of gnustl_static, will my std::string implementation be taken from libc++ or gnustl?
Ideally, I'd like to have a very stripped down version of a static c++ runtime with (c++_static) that only includes std::vector, std::string and std::map. I was actually planning to use something like -ffunction-sections as described here and #768.
Please advise and thank you.
Environment Details
Pkg.Desc = Android NDK
Pkg.Revision = r15c
Android Studio = 3.1.2
system: cmake Host OS: Arch Linux ($ uname -r % 4.18.5-arch1-1-ARCH)
Compiler: Clang++
STL: c++_static/c++_shared
Your concern is a very real one. But if handled properly, you can find a robust way out.
The warnings about using single C++ runtime across all libraries in the app (and the whole idea to define C++ support in NDK as APP_STL vs. most other flags such as LOCAL_CFLAGS or LOCAL_SHARED_LIBRARIES, are relevant for the native libraries that are connected. JNI libraries that never communicate directly (except through their corresponding Java layers) can use different C++ runtimes. Another point is that normal build will only package one C++ runtime shared lib into the APK. Note that versioning is also a potential hazard: if a developer who adds your library uses a different NDK release, there might be collisions or unexpected side effects when his version of STL runtime works with your code.
Therefore, to achieve maximum flexibility, your library should use a static C++ runtime. This may effect the size of the binary, but if, as you say, you use only a limited subset of STL, this extra will be rather small.
The bottom line, you will have minimum to worry about if build your shared library with libc++_static.

how to use mkfifo using Android's NDK

Recently I upgraded the NDK and now my app crashes with missing symbol mkfifo:
E/dalvikvm(2031): dlopen("/data/app-lib/...mylib.so") failed: Cannot load library: soinfo_relocate(linker.cpp:975): cannot locate symbol "mkfifo" referenced by "mylib.so"...
The older platforms mkfifo was defined inline in sys/stat.h
static __inline__ int mkfifo(const char *__p, mode_t __m) {
return mknod(__p, (__m & ~S_IFMT) | S_IFIFO, (dev_t)0);
}
But in platform version 21 it was changed to just an extern decleration:
extern int mkfifo(const char*, mode_t);
So that explains the missing symbol exception... my question is how do I fix it?
This happens if you build against the android-21 platform headers. Set APP_PLATFORM in jni/Application.mk to an older version, to build using the old headers, to make sure you only link to functions available earlier.
(Before android-21, the C library features and headers didn't really change significantly, so for the normal C library functions, it doesn't matter if you build targeting android-3 or android-20.)
This has been reported and is intentional behavior, see e.g. https://code.google.com/p/android/issues/detail?id=73725.
If you don't need to use new features from android-21, just build using older headers. (It doesn't matter that you're targeting an older platform version if you want to try to build for e.g. arm64-v8a or x86_64 that didn't exist before; ndk-build would build the 32 bit parts using the older target, and the 64 bit ones using the oldest target that supports them.)
In case you want to try to use new features from the android-21 platform conditionally if running on such a platform, you probably need to use dlopen and dlsym to load it conditionally anyway, so then you need to duplicate the other definitions from the new headers as well, to allow you to build using the older platform headers.
I've tried mstorsjo's fix and it seems to work, however I was a bit concerned that from the link he posted it seems that Google doesn't really think this is a good idea. As a result I did a bit more digging and it seems like the 'proper' fix is to ship multiple APKs, with (at least) one targeting android-20 and below, and another targeting android-21 and above.
The problem arises from a change in the NDK to force the use of the 'fPIE' option when performing an NDK build. From the NDK 10d release notes:
Introduced the requirement, starting from API level 21, to use -fPIE -pie when building. In API levels 16 and higher, ndk-build uses PIE when building. This change has a number of implications, which are discussed in Developer Preview Issue 888. These implications do not apply to shared libraries.
If you look at the Developer Preview Issue 888, it states the following:
Bionic commit 76e289c026f and its predecessor, 2aebf5429bb, require all dynamically linked native executables to be built with -fPIE -pie. This has a number of possibly-unintended side effects, including:
Old/unmaintained apps that worked correctly under KitKat may now fail to run under "L". This could affect even simple apps that do not use the network, handle untrusted data, or target the new "L" SDK API.
Actively maintained apps that wish to target "L" must ship PIE executables or static executables. If an app wants to target ICS or below, it must also ship non-PIE executables or static executables. Even a simple "Hello world" program built with -fPIE -pie will segfault on ICS and GB.
Obviously you may prefer to go with the previous solution but just thought it was worth noting.

Selective renderscript libraries

I've been working with renderscript in my project for a while now. In a recent effort to minimize APK size, I started wondering and researching whether the renderscript native libraries (libRSSupport.so and librsjni.so) - often bundled within the APK, can be omitted for build-targets such as x86 and mips, which are not necessary for release versions of the APK? (note: the libs are added to the APK regardless of the value of APP_ABI set within Application.mk)
I have come across blogs (much like this one - http://ph0b.com/android-studio-gradle-and-ndk-integration) seemingly describing how that can be achieved using gradle. But what about projects not using gradle (as my own)? Does anybody know a way -- for example, perhaps an undocumented variable that can be added to the project.properties?
Any help will be appreciated.
You really cannot remove those libraries, as they are needed for the app to run correctly on other non-ARM devices.

STLport and Android NDK - STLport loaded as static, Linux/gcc ld reports "multiple definitions"

I've looked thru a lot of material on Android NDK and STLport. I have complex app, java+native code, which loads STLport (a c++ standard library port). The original codebase had "APP_STL := stlport_static" in the Application.mk in the project's "jni" subdir. Causes ld to load the lib static. This caused many compile failures, in current SDK/NDK.
Tried to load as a dynamic lib, as per a suggestion. (In "../jni/Application.mk", set "APP_STL := stlport_shared") With this, I get a clean compile, and load, and the app runs flawlessly on the Android armeabi-v7a emulator, if I disable checkJNI on the "dalvik" virtual machine.
But once I enable checkJNI, I get an "unsatisfiedLinkError" on the libapplication.so, which looks like it might result from STLport being dynamically loaded. So, I want to load STLport in static mode (logcat reports this after several other libs successfully loaded). During the build, compile is ok, but I am getting two multiple definition errors, specifically: "multiple definition of 'vtable for std::bad_exception' " and of 'std::exception::~exception()'. (I have also tried using "gnustl_static").
I am using gcc version 4.3.0 and make version 3.81, command line mode, and small wrapper around build-ndk, for android ndk-r9c, with a build target version of android-8, "ant" to build the .apk file, and so on.
Someone who has more familiarity with Android than me (I am a complete noob) might have seen this before. If so, please advise. Thanx. - Rus
It's definitely possible to use stlport_static with NDK r9c. What object files are mentioned with multiple definition errors? Maybe, you are using some prebuilt libraries? Maybe, the gcc version 4.3 is problematic? Why don't you use the default (gcc 4.8)?
With that, the NDK document explicitly encourages use of shared STL, but you must not forget to call System.loadLibrary() in correct order:
System.loadLibrary("stlport_shared");
System.loadLibrary("Rusfuture");

How to build Android NDK .so without STL?

I'm using the newest Android NDK r6b to build my shared object. This library does not use any kind of STL at all, but resulting .so includes many STL stuff like std::bad_alloc_what(void) and many more, which increases size of binary greatly. Also release builds include this garbage. APP_STL not defined anywhere, also the NDK r5b produces small binary with used functions only. Is it a bug of r6b? How can I build with r6b without STL stuff?
It seems that there is a bug in NDK r6b and it always builds libraries with exceptions support, even if -fno-exceptions is explicitly specified.
See this question for details: Android NDK produce unreasonable big binaries, how to optimize .so size?
If you are using, say, new then you are implicitly using the standard library for the std::bad_alloc exception. Unless you call the no-throw version of new, which would instead use std::nothrow. If you don't use the standard library, then it won't get linked. Just make sure you don't, if that's what you want, or perhaps just move to C?

Categories

Resources