I developed a Java tool and it has many JNI functions, I am getting JNI crashes often. Is there any possibility to avoid those crashes or to catch these crashes as exceptions. I surfed internet and found it is possible through signal processing, signal chanining, sigaction(), etc. But I could not get a reliable source to direct me. Please do guide me on this.
Asked
Active
Viewed 3,389 times
1 Answers
1
JNI exceptions are considered as signals. You could set up your signal handlers by sigaction
and then you could try to unwind the crash stack, for example by libcorkscrew
, to save it on the disk. After that you could invoke a Java method via JNI interfaces to process the info you saved.
Sample:
int watched_signals[] = { SIGABRT, SIGILL, SIGSEGV, SIGINT, SIGKILL };
void sighandler_func(int sig, siginfo_t* sig_info, void* ptr)
{
// Dump the callstack by libcorkscrew
...
// Call a JNI interface to process the stack info
...
}
struct sigaction sighandler;
sighandler.sa_sigaction = &sighandler_func;
sighandler.sa_mask = 0;
sighandler.sa_flags = SA_SIGINFO | SA_ONSTACK;
for(int signal : watched_signals)
{
sigaction(signal, &sighandler, nullptr);
}
Suppose you have involved libcorkscrew into you ndk project then you could get the crash stack:
#include <dlfcn.h>
#include <ucontext.h>
#include <corkscrew/backtrace.h>
#include <backtrace-arch.h>
void dump_stack(int sig, siginfo_t* sig_info, void* ptr)
{
const size_t BACKTRACE_FRAMES_MAX = 0xFF;
static backtrace_frame_t frames[BACKTRACE_FRAMES_MAX];
static backtrace_symbol_t symbols[BACKTRACE_FRAMES_MAX];
map_info_t* const info = acquire_my_map_info_list();
const ssize_t size = unwind_backtrace_signal_arch(sig_info, ptr, info, frames, 0, BACKTRACE_FRAMES_MAX);
get_backtrace_symbols(frames, size, symbols);
for (int i = 0; i < size; i++)
{
backtrace_symbol_t& symbol = symbols[i];
// You could change the printf to fwrite if you want to save the info on disk
printf("#%02d pc %08X %s (%s+%d)",
i,
symbol.relative_pc,
symbol.map_name ? symbol.map_name : "<unknown>",
symbol.demangled_name ? symbol.demangled_name : symbol.symbol_name,
symbol.relative_pc - symbol.relative_symbol_addr);
}
free_backtrace_symbols(symbols, size);
release_my_map_info_list(info);
}
Even through you could continue the program after you handled the signal but I strongly suggest you to save the info on disk and process it in the next app launch. Because most of the time you program would fail when a signal raised.

jayatubi
- 1,972
- 1
- 21
- 51
-
Can you give a simple example code or link to understand the concept better? – user3201343 May 07 '15 at 15:52
-
Since you mentioned the JNI I supposed you have the NDK project been involved in your project. And then you could add the snippet into any of you c/cpp source code. For most cases you'd better put it in the `JNI_OnLoad` which is the entry point of your native code. – jayatubi May 08 '15 at 06:13
-
Thank you for your update, I am new to JNI implementations. I could not understand it. Where the code snippet need to be append in my code? `Sample.java` ` Sample{` ` native void callJavatoC();` } Sample.C JNIEXPORT void Java_Class_callJavatoC(JNIEnv* env, jobject obj) { "place where crashes occur" }` – user3201343 May 08 '15 at 06:17
-
If you just want to debug your native code please refer to the ndk-gdb: http://stackoverflow.com/questions/10534367/how-to-get-ndk-gdb-working-on-android If you want to make you app to catch the unexpected native crashes try to add the snippet at the beginning of your `JNI_OnLoad`. Then when the crash happens you code get the info from `adb logcat` or the file on disk, which depends on your choice. – jayatubi May 08 '15 at 06:19
-
Is there any way to find the reason for the crash using the hs_err* report? – user3201343 May 08 '15 at 06:25
-
Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/77280/discussion-between-user3201343-and-jayatubi). – user3201343 May 08 '15 at 06:27