JNI exception handling
Difference between JNI exception and JAVA exception handling
- JAVA has exception handling mechanism, but JNI does not.
- If exceptions are not captured in JAVA, subsequent code will not execute, and JNI will execute
- JAVA compile-time exceptions are those that declare an exception in the method display. The compiler requires the capture that must be displayed when calling.
Examples of JNI Exceptions
package org.professor.jni.java; public class TestException { public native void testException(); public void exceptionCallback() { int a = 20 / 0; System.out.println("--->" + a); } } package org.professor.jni; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import org.professor.jni.java.TestException; public class MainActivity extends AppCompatActivity { // Used to load the 'native-lib' library on application startup. static { // lib+native-lib+.so //libnative-lib.so System.loadLibrary("hello-jni"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = (TextView) findViewById(R.id.sample_text); // tv.setText(stringFromJNI()); TestException testException = new TestException(); try { testException.testException(); } catch (Exception e) { e.printStackTrace(); } } }
#include <jni.h> #include <android/log.h> #ifndef ANDROIDJNIDEMO_TEST_THROW_EXCEPTION_H #define ANDROIDJNIDEMO_TEST_THROW_EXCEPTION_H #define LOG_D(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOG_I(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOG_W(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) #define LOG_E(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #ifdef __cplusplus extern "C" { #endif /* * * Class: org_professor_jni_java_TestException * Method: occorException * Signature: ()V */ JNIEXPORT void JNICALL Java_org_professor_jni_java_TestException_testException (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif //ANDROIDJNIDEMO_TEST_THROW_EXCEPTION_H //------- partition line #include <jni.h> #include <test_throw_exception.h> #include <stdio.h> #define LOG_TAG "EXCEPTION" JNIEXPORT void JNICALL Java_org_professor_jni_java_TestException_testException(JNIEnv *env, jobject instance) { jclass exception_clazz = (*env)->FindClass(env, "org/professor/jni/java/TestException"); if (NULL == exception_clazz) { LOG_D("NOT FIND EXCEPTION CLASS"); return; } jmethodID test_method_id = (*env)->GetMethodID(env, exception_clazz, "exceptionCallback", "()V"); if (NULL == test_method_id) { LOG_E("NOT FIND TEXT METHOD ID"); return; } jmethodID default_constructor_method_id = (*env)->GetMethodID(env, exception_clazz, "<init>", "()V"); if (NULL == default_constructor_method_id) { LOG_I("NOT FIND DEFAULT CONSTRUCTOR ID "); return; } jobject test_exception_instance = (*env)->NewObject(env, exception_clazz, default_constructor_method_id); if (NULL == test_exception_instance) { LOG_W("NOT FIND TEST EXCEPTION INSTANCE"); return; } (*env)->CallVoidMethod(env, test_exception_instance, test_method_id); LOG_E("In C: CALL exceptionCallback Method!"); // If (* env) - > ExceptionCheck (env) {// Check if the JNI call throws an exception // (*env)->ExceptionDescribe(env); //// (* env) - > ExceptionClear (env); // Clears the exception that was thrown, and does not print the stack information of the exception at the Java layer // If not cleared, the exception stack information thrown by the subsequent call to ThrowNew overrides the previous exception information. //// (* env) - > ThrowNew (env, (* env) - > FindClass (env, "java/lang/Exception"), "Exceptions thrown by JNI!" ";// After clearing, you can throw your own exception, if not cleared, the exception stack information thrown by the subsequent call to ThrowNew will override the previous exception information. // //return; // } jthrowable throwable = (*env)->ExceptionOccurred(env); if (NULL != throwable) { (*env)->ExceptionDescribe(env); // (*env)->ExceptionClear(env); } LOG_E("In C: CALL exceptionCallback Method! end"); (*env)->DeleteLocalRef(env, exception_clazz); (*env)->DeleteLocalRef(env, test_exception_instance); }
Analysis:
- First, in Java code, we define a TestException class, which defines a native method and a common method, in which an exception ArithmeticException is normally thrown.
- The exceptionCallback method is called in the native code and checked for exceptions (memory checking and code commenting can be done in two ways).
summary
-
When a JNI function is called, it must first check, process and clear exceptions before making other JNI function calls, otherwise unpredictable results will be produced.
-
Once an exception occurs, it returns immediately and lets the caller handle the exception. Or call Exception Clear to clear the exception and execute your own exception handling code.
-
Summary of JNI functions related to exception handling:
- ExceptionCheck: Check if an exception has occurred and return JNI_TRUE if there is an exception, or JNI_FALSE if there is an exception
- Exception Occurred: Check if an exception has occurred and return a reference to the exception with an exception, or NULL
- ExceptionDescribe: Print stack information for exceptions
- Exception Clear: Clear exception stack information
- ThrowNew: Triggers an exception in the current thread and customizes the output of exception information jint (JNICALL *ThrowNew) (JNIEnv *env, jclass clazz, const char *msg);
- Throw: Discard an existing exception object and trigger a new exception in the current thread jint (JNICALL *Throw) (JNIEnv *env, jthrowable obj);
- FatalError: A fatal exception that is used to output an exception message and terminate the current VM instance (that is, exit the program) void (JNICALL *FatalError) (JNIEnv *env, const char *msg);