Replacing JNI crashes on exceptions on Android

I developed an Android app that uses its own C library. I could compile it all with JNI and everything works smoothly.

However, from time to time, the native C library crashes (most often with SIGSEGV). This, in turn, leads to the failure of my application without any meaningful notifications to the user. What I would like to achieve is the following:

  • Capturing a signal in native code using a signal handler (sigaction) to prevent accidental failures
  • Throw an exception in the C library that Java can catch
  • Catch the exception in Java, create a meaningful warning message for the user, and run the application

In case this is useful to you, the JNI code runs in a separate thread (more precisely, inside AsyncTask).

I already checked http://blog.httrack.com/blog/2013/08/23/catching-posix-signals-on-android/ and https://github.com/xroche/coffeecatch but I can not compile it.

Following recommendations Best way to throw exceptions in JNI code? and How to catch the JNI Failure as an exception using the Signal processing engine in Java and https://www.developer.com/java/data/exception-handling-in-jni.html I followed these steps:

In my native code, I added the following function, which (as far as I know) sets the signal handler:

void initializeSignalHandler(JNIEnv* env){ int watched_signals[] = { SIGABRT, SIGILL, SIGSEGV, SIGINT, SIGKILL }; // 6, 4, 11, 2, 9 struct sigaction sighandler; memset(&sighandler, 0, sizeof(sighandler)); sighandler.sa_sigaction = &sighandler_func; sighandler.sa_mask = 0; sighandler.sa_flags = SA_SIGINFO | SA_ONSTACK; for(int ii=0; ii<5; ii++){ int signal = watched_signals[ii]; sigaction(signal, &sighandler, NULL); } env = env; } 

My function that processes these signals looks like this:

 void sighandler_func(int sig, siginfo_t* sig_info, void* ptr){ printerr("Sighandler: ", sig); jclass jcls = (*env)->FindClass(env, "java/lang/Error"); jboolean flag = (*env)->ExceptionCheck(env); if (flag) { (*env)->ExceptionClear(env); /* code to handle exception */ } if (jcls!=NULL){ printerr("Throwing exception"); (*env)->ThrowNew(env, jcls, "error message"); } } 

My critical JNI function starts by setting up a signal handler:

 JNIEXPORT jint JNICALL Java_android_playground_criticalFuction (JNIEnv *env, jclass c, jlong handle, jshortArray out_buffer){ // new signal handler struct sigaction sighandler; initializeSignalHandler(env); // ...here goes the critical code } 

When SIGILL occurs in my own C code, the following happens:

1) On my debug terminal, I get the following four messages

  • Sighandler: 4 (which corresponds to SIGILL)
  • Throw exception
  • Sighandler: 4
  • Sighandler: 11

2) The application window closes, but I do not receive a message from Android "Sorry ... was closed", which usually appears when the application crashes

I really don’t understand why I am getting the third and fourth alarm message, as I would suggest that this is an exception. Also, I think the exception never throws (in Java).

I get lost and any help is much appreciated.

+5
source share

Source: https://habr.com/ru/post/1274164/


All Articles