Android NDK: getting the backtrace - android

I'm developing the native application that works with Android via the NDK.
I need to call the backtrace() function when there is a crash. The problem is that there is no <execinfo.h> for the NDK.
Is there any other way to get that back trace?

Android have no backtrace(), but unwind.h is here to serve. Symbolization is possible via dladdr().
The following code is my simple implementation of backtrace (with no demangling):
#include <iostream>
#include <iomanip>
#include <unwind.h>
#include <dlfcn.h>
namespace {
struct BacktraceState
{
void** current;
void** end;
};
static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg)
{
BacktraceState* state = static_cast<BacktraceState*>(arg);
uintptr_t pc = _Unwind_GetIP(context);
if (pc) {
if (state->current == state->end) {
return _URC_END_OF_STACK;
} else {
*state->current++ = reinterpret_cast<void*>(pc);
}
}
return _URC_NO_REASON;
}
}
size_t captureBacktrace(void** buffer, size_t max)
{
BacktraceState state = {buffer, buffer + max};
_Unwind_Backtrace(unwindCallback, &state);
return state.current - buffer;
}
void dumpBacktrace(std::ostream& os, void** buffer, size_t count)
{
for (size_t idx = 0; idx < count; ++idx) {
const void* addr = buffer[idx];
const char* symbol = "";
Dl_info info;
if (dladdr(addr, &info) && info.dli_sname) {
symbol = info.dli_sname;
}
os << " #" << std::setw(2) << idx << ": " << addr << " " << symbol << "\n";
}
}
It may be used for backtracing into LogCat like
#include <sstream>
#include <android/log.h>
void backtraceToLogcat()
{
const size_t max = 30;
void* buffer[max];
std::ostringstream oss;
dumpBacktrace(oss, buffer, captureBacktrace(buffer, max));
__android_log_print(ANDROID_LOG_INFO, "app_name", "%s", oss.str().c_str());
}

Here is some working and complete code that implements dump_stack() by starting with Eugene Shapovalov's answer and does symbol lookups and C++ name demangling right on the device. This solution:
works with the NDK r10e (you don't need the complete Android AOSP source tree)
does NOT require any extra third-party libraries (no libunwind, libbacktrace, corkscrew, CallStack)
does NOT depend on any shared libraries being installed on the device (e.g. corkscrew, which got axed in Android 5)
does NOT force you to map addresses to symbols on your development machine; all symbol names are revealed on the Android device in your code
It uses these facilities, which are built into the NDK:
<unwind.h> header that is in the NDK toolchain/ dirs (NOT libunwind)
dladdr()
__cxxabiv1::__cxa_demangle() from <cxxabi.h> (see STLport note below)
So far, I tested this only with an arm-based Android 5.1 device and I called it only from my main program (not from a signal handler). I was using the default ndk-build which chooses gcc for the arm platform.
Please comment if you are able to make this work
on other Android OSes
from a SIGSEGV handler on crash (my goal was simply to print a stack trace on assertion failure)
using clang toolsets instead of gcc
Note the r10e NDK has <unwind.h> code for many architectures in both gcc and clang toolsets so the support looks broad.
The C++ symbol name demangling support depends on an __cxxabiv1::__cxa_demangle() function that comes from the C++ STL that is included with the NDK. This should work as-is if you are doing your Android build with the GNU STL (APP_STL := gnustl_static or gnustl_shared in Application.mk; see this page for more info). If you are currrently using no STL at all, simply add APP_STL := gnustl_static or gnustl_shared to Application.mk. If you are using STLport, you have to enjoy a special kind of fun (more below).
IMPORTANT: for this code to work, you must not use the -fvisibility=hidden gcc compiler option (at least in your debug builds). That option is commonly used to hide symbols from prying eyes in release builds.
Many people have noted that the ndk-build script strips symbols from your NDK .so whilst copying it to the libs/ directory of your project. That is true (using nm on the two copies of the .so gives very different results) HOWEVER this particular layer of stripping amazingly does not prevent the code below from working. Somehow even after stripping there are still symbols (as long as you remembered not to compile with -fvisibility=hidden). They show up with nm -D.
Other posts on this topic have discussed other compiler options like -funwind-tables. I didn't find that I needed to set any such option. The default ndk-build options worked.
To use this code, replace _my_log() with your favorite logging or string function.
STLport users see special notes below.
#include <unwind.h>
#include <dlfcn.h>
#include <cxxabi.h>
struct android_backtrace_state
{
void **current;
void **end;
};
_Unwind_Reason_Code android_unwind_callback(struct _Unwind_Context* context,
void* arg)
{
android_backtrace_state* state = (android_backtrace_state *)arg;
uintptr_t pc = _Unwind_GetIP(context);
if (pc)
{
if (state->current == state->end)
{
return _URC_END_OF_STACK;
}
else
{
*state->current++ = reinterpret_cast<void*>(pc);
}
}
return _URC_NO_REASON;
}
void dump_stack(void)
{
_my_log("android stack dump");
const int max = 100;
void* buffer[max];
android_backtrace_state state;
state.current = buffer;
state.end = buffer + max;
_Unwind_Backtrace(android_unwind_callback, &state);
int count = (int)(state.current - buffer);
for (int idx = 0; idx < count; idx++)
{
const void* addr = buffer[idx];
const char* symbol = "";
Dl_info info;
if (dladdr(addr, &info) && info.dli_sname)
{
symbol = info.dli_sname;
}
int status = 0;
char *demangled = __cxxabiv1::__cxa_demangle(symbol, 0, 0, &status);
_my_log("%03d: 0x%p %s",
idx,
addr,
(NULL != demangled && 0 == status) ?
demangled : symbol);
if (NULL != demangled)
free(demangled);
}
_my_log("android stack dump done");
}
What if you are using STLport STL instead of GNU STL?
Sucks to be you (and me). There are two problems:
The first problem is that STLport lacks the __cxxabiv1::__cxa_demangle() call from <cxxabi.h>. You will need to download two source files cp-demangle.c and cp-demangle.h from this repository and place them in a demangle/ subdirectory under your source, then do this instead of #include <cxxabi.h>:
#define IN_LIBGCC2 1 // means we want to define __cxxabiv1::__cxa_demangle
namespace __cxxabiv1
{
extern "C"
{
#include "demangle/cp-demangle.c"
}
}
The second problem is more nasty. It turns out there's not one, not two, but THREE different, incompatible types of <unwind.h> in the NDK. And you guessed it, the <unwind.h> in STLport (actually it's in the gabi++ library that comes along for a ride when you choose STLport) is incompatible. The fact that the STLport/gabi++ includes come before the toolchain includes (see your ndk-build output's -I options) means that STLport is preventing you from using the real <unwind.h>. I could not find any better solution than to go in and hack the filenames inside my installed NDK:
sources/cxx-stl/gabi++/include/unwind.h to sources/cxx-stl/gabi++/include/unwind.h.NOT
sources/cxx-stl/gabi++/include/unwind-arm.h to sources/cxx-stl/gabi++/include/unwind-arm.h.NOT
sources/cxx-stl/gabi++/include/unwind-itanium.h to sources/cxx-stl/gabi++/include/unwind-itanium.h.NOT
I'm sure there's some more elegant solution, however I suspect switching the order of the -I compiler options will probably create other problems, since STLs generally want to override toolchain include files.
Enjoy!

backtrace() is a non-standard Glibc extension, and even then somewhat shaky on ARM (you need to have built everything with -funwind-tables, I think, and then have a somewhat new Glibc?)
As far as I know, this function is not included in the Bionic C library used by Android.
You could try pulling the source for Glibc backtrace into your project, and then rebuilding the interesting things with the unwind table, but it sounds like hard work to me.
If you have debug info, you could try launching GDB with a script that attaches to your process, and prints a backtrace that way, but I have no idea if GDB works on Android (although Android is basically Linux, so that much id fine, the installation details may be problematic?) You may get further by dumping core somehow (does Bionic support that?) and analysing it after-the-fact.

Here is a crazy one-line method for getting a fantastically detailed stack trace that includes both C/C++ (native) and Java: abuse JNI
env->FindClass(NULL);
As long as your app is compiled debug, or otherwise uses Android's CheckJNI, this erroneous call will trigger Android's built-in JNI checker which will produce a gorgeous stack trace on the console (from the "art" log source). This stack trace is done inside Android's libart.so using all the latest technologies and bells and whistles that are not easily available to lowly NDK users like us.
You can enable CheckJNI even for apps that are not compiled debug. See this google FAQ for details.
I do not know if this trick works from a SIGSEGV handler (from SIGSEGV you might get a stack trace of the wrong stack, or maybe art will not be triggered at all) but it is worth a try.
If you need a solution that makes the stack trace available in your code (e.g. so you can send it over the net or log it), see my other answer in this same question.

You can use the CallStack:
#include <utils/CallStack.h>
void log_backtrace()
{
CallStack cs;
cs.update(2);
cs.dump();
}
Results will need de-mangling by c++filt or something similar:
D/CallStack( 2277): #08 0x0x40b09ac8: <_ZN7android15TimedEventQueue11threadEntryEv>+0x0x40b09961
D/CallStack( 2277): #09 0x0x40b09b0c: <_ZN7android15TimedEventQueue13ThreadWrapperEPv>+0x0x40b09af9
you#work>$ c++filt _ZN7android15TimedEventQueue11threadEntryEv _ZN7android15TimedEventQueue13ThreadWrapperEPv
android::TimedEventQueue::threadEntry()
android::TimedEventQueue::ThreadWrapper(void*)

Here is how you capture backtrace on 32-bit ARM, using libunwind, that is bundled with modern Android NDKs (such as NDK r16b).
// Android NDK r16b contains "libunwind.a" for armeabi-v7a ABI.
// This library is even silently linked in by the ndk-build,
// so we don't have to add it manually in "Android.mk".
// We can use this library, but we need matching headers,
// namely "libunwind.h" and "__libunwind_config.h".
// For NDK r16b, the headers can be fetched here:
// https://android.googlesource.com/platform/external/libunwind_llvm/+/ndk-r16/include/
#include "libunwind.h"
struct BacktraceState {
const ucontext_t* signal_ucontext;
size_t address_count = 0;
static const size_t address_count_max = 30;
uintptr_t addresses[address_count_max] = {};
BacktraceState(const ucontext_t* ucontext) : signal_ucontext(ucontext) {}
bool AddAddress(uintptr_t ip) {
// No more space in the storage. Fail.
if (address_count >= address_count_max)
return false;
// Add the address to the storage.
addresses[address_count++] = ip;
return true;
}
};
void CaptureBacktraceUsingLibUnwind(BacktraceState* state) {
assert(state);
// Initialize unw_context and unw_cursor.
unw_context_t unw_context = {};
unw_getcontext(&unw_context);
unw_cursor_t unw_cursor = {};
unw_init_local(&unw_cursor, &unw_context);
// Get more contexts.
const ucontext_t* signal_ucontext = state->signal_ucontext;
assert(signal_ucontext);
const sigcontext* signal_mcontext = &(signal_ucontext->uc_mcontext);
assert(signal_mcontext);
// Set registers.
unw_set_reg(&unw_cursor, UNW_ARM_R0, signal_mcontext->arm_r0);
unw_set_reg(&unw_cursor, UNW_ARM_R1, signal_mcontext->arm_r1);
unw_set_reg(&unw_cursor, UNW_ARM_R2, signal_mcontext->arm_r2);
unw_set_reg(&unw_cursor, UNW_ARM_R3, signal_mcontext->arm_r3);
unw_set_reg(&unw_cursor, UNW_ARM_R4, signal_mcontext->arm_r4);
unw_set_reg(&unw_cursor, UNW_ARM_R5, signal_mcontext->arm_r5);
unw_set_reg(&unw_cursor, UNW_ARM_R6, signal_mcontext->arm_r6);
unw_set_reg(&unw_cursor, UNW_ARM_R7, signal_mcontext->arm_r7);
unw_set_reg(&unw_cursor, UNW_ARM_R8, signal_mcontext->arm_r8);
unw_set_reg(&unw_cursor, UNW_ARM_R9, signal_mcontext->arm_r9);
unw_set_reg(&unw_cursor, UNW_ARM_R10, signal_mcontext->arm_r10);
unw_set_reg(&unw_cursor, UNW_ARM_R11, signal_mcontext->arm_fp);
unw_set_reg(&unw_cursor, UNW_ARM_R12, signal_mcontext->arm_ip);
unw_set_reg(&unw_cursor, UNW_ARM_R13, signal_mcontext->arm_sp);
unw_set_reg(&unw_cursor, UNW_ARM_R14, signal_mcontext->arm_lr);
unw_set_reg(&unw_cursor, UNW_ARM_R15, signal_mcontext->arm_pc);
unw_set_reg(&unw_cursor, UNW_REG_IP, signal_mcontext->arm_pc);
unw_set_reg(&unw_cursor, UNW_REG_SP, signal_mcontext->arm_sp);
// unw_step() does not return the first IP,
// the address of the instruction which caused the crash.
// Thus let's add this address manually.
state->AddAddress(signal_mcontext->arm_pc);
// Unwind frames one by one, going up the frame stack.
while (unw_step(&unw_cursor) > 0) {
unw_word_t ip = 0;
unw_get_reg(&unw_cursor, UNW_REG_IP, &ip);
bool ok = state->AddAddress(ip);
if (!ok)
break;
}
}
void SigActionHandler(int sig, siginfo_t* info, void* ucontext) {
const ucontext_t* signal_ucontext = (const ucontext_t*)ucontext;
assert(signal_ucontext);
BacktraceState backtrace_state(signal_ucontext);
CaptureBacktraceUsingLibUnwind(&backtrace_state);
exit(0);
}
Here is a sample backtrace testing app with 3 implemented backtracing methods, including the method shown above.
https://github.com/alexeikh/android-ndk-backtrace-test

If you just want a few (eg 2 - 5) topmost call frames and if your GCC is recent enough, you might consider using some return address or frame address builtins.
(But I don't know much about Android, so I could be wrong)

Related

Providing a JVM for MediaStreamer2 Console Application on Android

I am working on an Android firmware for an embedded device which streams an encoded video signal using rtp. The underlying library is MediaStreamer2 because it comes with Android support, various codecs and libortp. Therefore I integrated libmediastreamer and its dependencies into my firmware build process.
As a second step, I wrote a simple Android command line application as a PoC which streams audio or video through the network. Unfortunatly, the first call to ms_init() fails due to:
bctbx-fatal-Calling ms_get_jni_env() while no jvm has been set using ms_set_jvm()
Digging a little deeper into the problem, it seems Androids version of libmediastreamer was designed from an NDK point of view: It can be called as a part of an Android app and therefore automatically gets a reference to the JVM (DVM?). Unfortunatly, this is not my use case.
I tried to to remove the dependencies (Querying Sdk version, hardware echo cancelation support, etc.) without success. So my next approach would be starting a VM manually and passing it to the library. I tried Oracles APIs like:
JNIEnv env;
JavaVM vm;
JavaVMInitArgs vm_args;
JavaVMOption options[4];
options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-verbose:jni";
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 4;
vm_args.ignoreUnrecognized = TRUE;
jint res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
But the application quits with a simple "aborted". Nevertheless, I am not sure whether this is a way to go because its Android and Dalvik world.
Any suggestions?
It is possible to build executable for shell on Android on both rooted and non-rooted devices, see reference How to build an executable for Android shell
.
Try below code and build it using NDK to get an executable:
#include <jni.h>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char **argv) {
JavaVMOption jvmopt[1];
jvmopt[0].optionString = "-Djava.class.path=" + ".";
JavaVMInitArgs vmArgs;
vmArgs.version = JNI_VERSION_1_2;
vmArgs.nOptions = 1;
vmArgs.options = jvmopt;
vmArgs.ignoreUnrecognized = JNI_TRUE;
// Create the JVM
JavaVM *javaVM;
JNIEnv *jniEnv;
long flag = JNI_CreateJavaVM(&javaVM, (void**)
&jniEnv, &vmArgs);
if (flag == JNI_ERR) {
cout << "Error creating VM. Exiting...\n";
return 1;
}
/** ----------------------------------------------
* Put your own JNI related code from here if any.
* -----------------------------------------------
**/
javaVM->DestroyJavaVM();
return 0;
}
Do a check on <jni.h> about the interfaces you can use, e.g.
/*
* VM initialization functions.
*
* Note these are the only symbols exported for JNI by the VM.
*/
jint JNI_GetDefaultJavaVMInitArgs(void*);
jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);
jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*);
You can refer to below to see if they are helpful:
how-to-create-a-jvm-instance-in-jni
https://calebfenton.github.io/2017/04/05/creating_java_vm_from_android_native_code/

CMAKE_BUILD_TYPE Release: strange results

We are creating an Android app to compare execution time between ART and native code. We are using Android Studio and CMake for compiling C/C++.
When in CMakeList.txt we set the flag
set(CMAKE_BUILD_TYPE Release)
in some algorithms (Primality Test and Fibonacci) the execution time drastically drop to 0ms for all different input.
Here the native lib
bool flag = false;
extern "C" JNIEXPORT void JNICALL Java_javacpp_cmr_com_sdkvsndk_MainActivity_cancel(JNIEnv *env, jobject obj) {
flag = true;
}
extern "C" JNIEXPORT jlong JNICALL Java_javacpp_cmr_com_sdkvsndk_MainActivity_primalityTest(JNIEnv *env, jobject obj, jlong r) {
if(r < 0) return -1L;
timeval start, stop;
long long t;
gettimeofday(&start, NULL);
bool prime = true;
unsigned long long sr = (unsigned long long) sqrt(r);
for (unsigned long long i = 2; (i < sr) && prime; i++) {
if (flag) return -1;
if (r % i == 0) prime = false;
}
gettimeofday(&stop, NULL);
t = (stop.tv_sec - start.tv_sec) * 1000;
t += (long long) ((stop.tv_usec - start.tv_usec) / 1000)
return (jlong) t;
}
flag is a flag that is set true when we terminate the asyncTask that execute the algorithm.
I can not figure how this is possible. Any suggestion? Thank you.
This is because by default your CMake project is build with Debug type. In this type the debugging information is generated as well as optimisations are disabled (-O0 -g flags to gcc).
This is to enable you to step trough your C++ code line by line as it was written by you. If you change the type to Release the optimisations are turned on and the debug info is not included with the binary.
The optimisations make the code run so fast, no matter how well you think you wrote something, the compiler is still ahead of you and will make it better. Those optimisations however will show erratic behaviour when the code is debugged, lines executed out of order, or not at all, variables not showing in watches or shown wrong, this is not nice for debugging.
The missing debug info means the binary is lighter but if you need to debug it better practice some assembly since any information on what line of C++ resulted in these assembly instructions is lost. As a side note there is also RelWithDebugInfo build type in case you really need to debug the optimised code.
Normally the Android Studio should take care of the appropriate build type for you so there is no need to fiddle with that.
You can dump the compilation commands used to build the C/C++ source files using:
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) in the CMakeLists.txt which will create a compile_commands.json in the build directory.
You can try different combination of the "CMAKE_BUILD_TYPE" and save the generated compile_commands.json for different build types for different compiler flags for optimizations, debugging etc.

API to get android system properties is removed in arm64 platforms

I am using __system_property_get() from sys/system_properties.h to get a system property. I am trying to use r10c ndk because I need arm64 toolchain.
__system_property_get() is defined in libc.so. Below is the readelf output of libc.so for armv5/armv7a.
readelf -Ws libc.so | grep property_get
194: 00009100 20 FUNC GLOBAL DEFAULT 4 __system_property_get
198: 00009100 20 FUNC GLOBAL DEFAULT 4 __system_property_get
But, looks like it has been removed for arm64 version! I am getting a linker error saying it is not defined. I analyzed all the shared libraries of arm64 but none of them have that symbol.
Is there an alternate API to get the system property in the native code?
Thank you!
It's useful API for native apps, just as it is for Java apps, it originates from the native side (see http://rxwen.blogspot.com/2010/01/android-property-system.html), and other Android system code uses it, so it's unlikely to go away soon.
#include <android/log.h>
#include <dlfcn.h>
#if (__ANDROID_API__ >= 21)
// Android 'L' makes __system_property_get a non-global symbol.
// Here we provide a stub which loads the symbol from libc via dlsym.
typedef int (*PFN_SYSTEM_PROP_GET)(const char *, char *);
int __system_property_get(const char* name, char* value)
{
static PFN_SYSTEM_PROP_GET __real_system_property_get = NULL;
if (!__real_system_property_get) {
// libc.so should already be open, get a handle to it.
void *handle = dlopen("libc.so", RTLD_NOLOAD);
if (!handle) {
__android_log_print(ANDROID_LOG_ERROR, "foobar", "Cannot dlopen libc.so: %s.\n", dlerror());
} else {
__real_system_property_get = (PFN_SYSTEM_PROP_GET)dlsym(handle, "__system_property_get");
}
if (!__real_system_property_get) {
__android_log_print(ANDROID_LOG_ERROR, "foobar", "Cannot resolve __system_property_get(): %s.\n", dlerror());
}
}
if (!__real_system_property_get) return (0);
return (*__real_system_property_get)(name, value);
}
#endif // __ANDROID_API__ >= 21
In older NDKs this was not an officially supported API. It was mistakenly exposed to the 32-bit ABIs early on, but wasn't exposed to the 64-bit ABIs until it was officially supported. Regardless, it is exposed by the system at all API levels, so newer NDKs are able to use this regardless of ABI or minSdkVersion.
Confirming #bleater's answer as a workaround for the unexposed __system_properties_* symbols: dlopen libc and dlsym as needed.

Getting OS version with NDK in C

I'm writing a C program which I want to execute on my Desktop running Linux and also on an Android device.
I have to make some Desktop specific things and some Android specific things.
My question is, is there a way to get the OS version in C so I can handle if the program is executed on the Desktop or on the Android device?
In your native code, you could use property_get(), something like this:
#include <cutils/properties.h>
// ...
int myfunction() {
char sdk_ver_str[PROPERTY_VALUE_MAX] = "0";
property_get("ro.build.version.sdk", sdk_ver_str, "0");
sdk_ver = atoi(sdk_ver_str);
// ...
}
On desktop, property_get() should return empty string.
Note that in starting from Android 6, <cutils/properties.h> is not available in SDK, use __system_property_get as follows:
#include <sys/system_properties.h>
// ...
int myfunction() {
char sdk_ver_str[PROPERTY_VALUE_MAX];
if (__system_property_get("ro.build.version.sdk", sdk_ver_str)) {
sdk_ver = atoi(sdk_ver_str);
} else {
// Not running on Android or SDK version is not available
// ...
}
// ...
}
You can use adb shell getprop to see all possible Android properties. But, be aware that not all of them are supported by all devices.
UPDATE: If you don't need OS version, but simply want to tell if your C/C++ code is running on Android, very simple way to tell is to check if environment variable ANDROID_PROPERTY_WORKSPACE exists (on Android 7 or older), or if socket /dev/socket/property_service exists (Android 8 or newer), something like this:
include <stdlib.h>
include <unistd.h>
// ...
if (getenv("ANDROID_PROPERTY_WORKSPACE")) {
// running under Android 7 or older
} else if (access("/dev/socket/property_service", F_OK) == 0) {
// running under Android 8 or newer
} else {
// running on desktop
}
property_get() did not work for me, instead I used __system_property_get().
#include <sys/system_properties.h>
void foo() {
char osVersion[PROP_VALUE_MAX+1];
int osVersionLength = __system_property_get("ro.build.version.release", osVersion);
}
ro.build.version.release is a string like "6.0". You can also get ro.build.version.sdk to get the sdk level, which is a string like "23".
If you use the java native interface, you can use the java function to get the sdk version number, which is less dependent on android version.
int api_version( struct android_app *app ) {
JNIEnv* env;
app->activity->vm->AttachCurrentThread( &env, NULL );
// VERSION is a nested class within android.os.Build (hence "$" rather than "/")
jclass versionClass = env->FindClass("android/os/Build$VERSION" );
jfieldID sdkIntFieldID = env->GetStaticFieldID(versionClass, "SDK_INT", "I" );
int sdkInt = env->GetStaticIntField(versionClass, sdkIntFieldID );
app->activity->vm->DetachCurrentThread();
return sdkInt;
}
How about using AConfiguration_getSdkVersion() API?
#include <android/configuration.h>
...
auto apilevel = AConfiguration_getSdkVersion(app->config);
LOGI("Device API Level %d", apilevel);
NDK provide direct api to get app target sdk version or api level
android_get_device_api_level
android_get_application_target_sdk_version
See the ndk official document.

Does Android support thread?

Does Android support pthreads?
And why when i use -pthread option i see the linker error:
i686-android-linux/bin/ld: cannot find -lpthread
#include <pthread.h>
#include <cxxabi.h>
extern "C" int printf (const char *, ...);
int main()
{
try
{
pthread_exit (0);
}
catch (abi::__forced_unwind &)
{
printf ("caught forced unwind\n");
throw;
}
catch (...)
{
printf ("caught ...\n");
return 1;
}
}
As far as I could see in the docs you do not need to use "-pthread". Checkout following:
http://mobilepearls.com/labs/native-android-api/#pthreads
Info from NDK offical docs states (android-ndk-r8\docs\system\libc\OVERVIEW.html):
PThread implementation:
Bionic's C library comes with its own pthread implementation bundled in.
This is different from other historical C libraries which:
- place it in an external library (-lpthread)
- play linker tricks with weak symbols at dynamic link time
So keep in mind that Bionic includes directly pthread as opposed to standard way you are used to (with -lpthread).

Categories

Resources