• Android jni/ndk编程五:jni异常处理


    Java的编程中,我们经常会遇到各种的异常,也会处理各种的异常。处理异常在java中非常简单,我们通常会使用try-catch-finally来处理,也可以使用throw简单抛出一个异常。那么在jni编程的时候我们又是如何处理异常的呢?

    异常处理流程

    jni规范已经给我们做好了所有需要做的事情。回想一下处理异常的过程:

    1. 我们首先要在有可能产生异常的地方检测异常
    2. 处理异常 
      是的,我觉得异常的处理就是可以简单的总结为两步,在异常处理中我们通常会打印栈信息等。在jni编程中,异常处理的思路应该也与之类似,过程可用下图表示: 
      这里写图片描述 
      在jni中我么需要手动清除异常。因此,jni中异常的处理应该严格遵循:检查->处理->清除的流程,在图中我把清除也认为是处理的其中一步了。

    JNI中异常处理函数

    jni.h中有如下相关的函数的定义:

        jint        (*Throw)(JNIEnv*, jthrowable);
        jint        (*ThrowNew)(JNIEnv *, jclass, const char *);
        jthrowable  (*ExceptionOccurred)(JNIEnv*);
        void        (*ExceptionDescribe)(JNIEnv*);
        void        (*ExceptionClear)(JNIEnv*);
        void        (*FatalError)(JNIEnv*, const char*);

    此外,还有一个函数和他们没放在一起:

        jboolean    (*ExceptionCheck)(JNIEnv*);

    单从名字上我们可以知道用于检测异常的发生的函数有:

    • (ExceptionCheck)(JNIEnv);
    • (ExceptionOccurred)(JNIEnv); 
      用于清理异常的有:
    • (ExceptionClear)(JNIEnv); 
      用于跑出异常的有:
    • (Throw)(JNIEnv, jthrowable);
    • (ThrowNew)(JNIEnv , jclass, const char *);
    • (FatalError)(JNIEnv, const char*); 
      下面对以上函数做一个简单的介绍: 
      1> ExceptionCheck:检查是否发生了异常,若有异常返回JNI_TRUE,否则返回JNI_FALSE 
      2> ExceptionOccurred:检查是否发生了异常,若用异常返回该异常的引用,否则返回NULL 
      3> ExceptionDescribe:打印异常的堆栈信息 
      4> ExceptionClear:清除异常堆栈信息 
      5> ThrowNew:在当前线程触发一个异常,并自定义输出异常信息 
      6> Throw:丢弃一个现有的异常对象,在当前线程触发一个新的异常 
      7> FatalError:致命异常,用于输出一个异常信息,并终止当前VM实例(即退出程序)

    测试异常

    根据以上总结,我们写如下功能的测试代码: 
    native调用java中的方法,java中的方法抛出异常,我们在native中检测异常,检测到后抛出native中的异常,并清理异常。

    c代码

    void native_catchException(JNIEnv *env, jobject obj)
    {
        jthrowable exc;
        jclass cls = (*env)->GetObjectClass(env, obj);
        jmethodID mid =(*env)->GetMethodID(env, cls, "callbackException", "()V");
        if (mid == NULL) {
            return;
        }
        (*env)->CallVoidMethod(env, obj, mid);
        exc = (*env)->ExceptionOccurred(env);
        if (exc) {
            jclass newExcCls;
            (*env)->ExceptionDescribe(env);
            (*env)->ExceptionClear(env);
            newExcCls = (*env)->FindClass(env,"java/lang/IllegalArgumentException");
            if (newExcCls == NULL) {
                /* Unable to find the exception class, give up. */
                return;
            }
            (*env)->ThrowNew(env, newExcCls, "thrown from C code");
        }
    }
    
    
    
    static JNINativeMethod gMethods[] = {  
    ...
    {"exception","()V",(void *)native_catchException},
    };  

    代码的其他部分请参看之前的章节。

    java代码

        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            textView = (TextView) findViewById(R.id.text);
            try {
                exception();
            } catch (Exception e) {
                System.out.println("In Java:
    	" + e);
            }
        }
        private native void exception() throws IllegalArgumentException;
        private void callbackException() throws NullPointerException {
            throw new NullPointerException("MainActivity.callbackException");
        }

    输出

    09-26 10:58:50.012 23934-23934/com.jinwei.jnitesthello W/System.err: java.lang.NullPointerException: MainActivity.callbackException
    09-26 10:58:50.012 23934-23934/com.jinwei.jnitesthello W/System.err:     at com.jinwei.jnitesthello.MainActivity.callbackException(MainActivity.java:24)
    09-26 10:58:50.012 23934-23934/com.jinwei.jnitesthello W/System.err:     at com.jinwei.jnitesthello.MainActivity.exception(Native Method)
    09-26 10:58:50.012 23934-23934/com.jinwei.jnitesthello W/System.err:     at com.jinwei.jnitesthello.MainActivity.onCreate(MainActivity.java:32)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at android.app.Activity.performCreate(Activity.java:6299)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at android.app.ActivityThread.-wrap11(ActivityThread.java)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at android.os.Looper.loop(Looper.java:148)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5417)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:731)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:621)
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello I/System.out: In Java:
    09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello I/System.out:    java.lang.IllegalArgumentException: thrown from C code

    从输出中我们看到c代码中使用:(*env)->ThrowNew(env, newExcCls, “thrown from C code”);这行代码跑出了异常。然后java中的异常处理函数打印了栈的信息。

    工具函数

    JNI中抛异常很经典:找异常类,调用ThrowNew抛出之;所以,可以写一个工具函数。

    void
    JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg)
    {
        jclass cls = (*env)->FindClass(env, name);
        /* if cls is NULL, an exception has already been thrown */
        if (cls != NULL) {
            (*env)->ThrowNew(env, cls, msg);
        }
        /* free the local ref */
        (*env)->DeleteLocalRef(env, cls);
    }
  • 相关阅读:
    linux之正则表达式
    ssh远程连接centos
    centOS网络配置
    linux软件包的管理
    linux内存、进程管理
    cent_os_7进行磁盘分区
    linux文件压缩、磁盘分区、vi和软硬链接
    linux用户、群操作命令和文件权限修改
    c#控制台程序
    c#简易程序解释1
  • 原文地址:https://www.cnblogs.com/chenxibobo/p/6895489.html
Copyright © 2020-2023  润新知