2

I am trying to catch an error in native C++ code on Android. According to the docs FindClass returns NULL when class name cannot be find. But I got FATAL EXCEPTION: main java.lang.NoClassDefFoundError: fake/class and execution never reaches the if statement.

#include <string.h>
#include <jni.h>

extern "C"
void Java_com_example_MainActivity_testError(JNIEnv *env, jobject) {
    jclass clazz = env->FindClass("fake/class");
    // never gets here
    if (clazz == NULL) {
        return;
    }
}

Also this exception skips the try-catch block and crashes the app. My Java code:

static {
    System.loadLibrary("native-lib");
}

public native void testError();

...
try {
    testError();
} catch (Exception e) {
    // exception never get cought
}

Also I use cppFlags '-fexceptions'. Is there a proper way to catch this exception or recover from it so the app does not crash?

kosev
  • 2,125
  • 1
  • 20
  • 18
  • From: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#FindClass THROWS: NoClassDefFoundError: if no definition for a requested class or interface can be found. JNI has methods to see if a Java exception is being thrown and deal with it. The Java exception does not "become active" until the JNI method returns. – Richard Critten Oct 17 '16 at 22:28
  • java.lang.NoClassDefFoundError is not derived from java.lang.Exception but from java.lang.Error That's why your exception is not being caught. See https://docs.oracle.com/javase/7/docs/api/java/lang/NoClassDefFoundError.html – Richard Critten Oct 17 '16 at 22:32
  • Since you mention the `-fexceptions` flag, don't confuse Java and C++ exceptions - they're completely separate beasts. – zenzelezz Oct 18 '16 at 14:23

1 Answers1

2

First, to prevent native code from crashing on FindClass, etc. you have to use this code after every JNI call:

bool checkExc(JNIEnv *env) {
    if (env->ExceptionCheck()) {
        env->ExceptionDescribe(); // writes to logcat
        env->ExceptionClear();
        return true;
    }
    return false;
}

Actually, ExceptionClear() stops the crash. I have found the code on this answer https://stackoverflow.com/a/33777516/2424777

Second, to be sure to catch all crashes from native code, you have to use this try-catch. Credits @Richard Critten Also use it on all native function calls:

static {
    try {
        System.loadLibrary("native-lib");
    } catch (Error | Exception ignore) { }
}

And cppFlags '-fexceptions' has nothing to do it so you can remove it.

Community
  • 1
  • 1
kosev
  • 2,125
  • 1
  • 20
  • 18
  • You have saved my day, wish I could upvote x10, Am using the first option and working well. Is there a way to make it log in the `Error` category of Android studio logcat? because it's logging in the `Info` category which has too much logs and finding becomes difficult. – Geek Guy Feb 01 '19 at 15:38
  • it helped me a lot – Saeed Arianmanesh Feb 02 '21 at 15:32