注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

民主与科学

独立之人格,自由之思想

 
 
 

日志

 
 

如何在JNI中抛异常  

2011-10-05 17:03:46|  分类: 开发专题 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
在android的JNIHelp.h文件中声明四种可以向JVM抛异常的函数:
int jniThrowException(JNIEnv* env, const char* className,const char* msg)
int jniThrowNullPointerException(JNIEnv* env, char* msg)
int jniThrowIOException(JNIEnv* env, int errnum)
int jniThrowRuntimeException(JNIEnv* env, const char* msg)
注意虽然 const char* className它是字符串,但是它是要传到中使用,所以它必须和某个类相对应的。
以上4个函数的定义是JNIHelp.c文件中进行的。查看源码你会发现jniThrowNullPointerExceptionjniThrowRuntimeExceptionjniThrowIOException其实就是个特殊的jniThrowException其实它们是const char* className参数分别为"java/lang/NullPointerException"、"java/lang/RuntimeException"、"java/IO/IOException"的jniThrowException。
它们的使用也很简单,具体可以参照下面的示例代码。
另外注意,这里的抛异常函数并不是在抛异常的同时退出当前函数,而是在函数最终返回时,才真正的抛出异常。
示例1
android_database_SQLiteQuery.cpp文件中的native_fill_window函数
static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow, jint startPos, jint offsetParam)
{
//略
    if (statement == NULL) {
        LOGE("Invalid statement in fillWindow()");
        jniThrowException(env, "java/lang/IllegalStateException",
                          "Attempting to access a deactivated, closed, or empty cursor");
        return 0;
    }

    // Only do the binding if there is a valid offsetParam. If no binding needs to be done
    // offsetParam will be set to 0, an invliad value.
    if(offsetParam > 0) {
        // Bind the offset parameter, telling the program which row to start with
        err = sqlite3_bind_int(statement, offsetParam, startPos);
        if (err != SQLITE_OK) {
            LOGE("Unable to bind offset position, offsetParam = %d", offsetParam);
            jniThrowException(env, "java/lang/IllegalArgumentException",
                              sqlite3_errmsg(GET_HANDLE(env, object)));
            return 0;
        }
        LOG_WINDOW("Bound to startPos %d", startPos);
    } else {
        LOG_WINDOW("Not binding to startPos %d", startPos);
    }

    // Get the native window
    window = get_window_from_object(env, javaWindow);
    if (!window) {
        LOGE("Invalid CursorWindow");
        jniThrowException(env, "java/lang/IllegalArgumentException","Bad CursorWindow");
        return 0;
    }
    LOG_WINDOW("Window: numRows = %d, size = %d, freeSpace = %d", window->getNumRows(), window->size(), window->freeSpace());

    numColumns = sqlite3_column_count(statement);
    if (!window->setNumColumns(numColumns)) {
        LOGE("Failed to change column count from %d to %d", window->getNumColumns(), numColumns);
        jniThrowException(env, "java/lang/IllegalStateException", "numColumns mismatch");
        return 0;
    }
//略    
}
示例2
android_util_EventLog.cpp中的android_util_EventLog_readEvents函数
static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
                                             jintArray tags,
                                             jobject out) {
    if (tags == NULL || out == NULL) {
        jniThrowException(env, "java/lang/NullPointerException", NULL);
        return;
    }

    int fd = open("/dev/" LOGGER_LOG_EVENTS, O_RDONLY | O_NONBLOCK);
    if (fd < 0) {
        jniThrowIOException(env, errno);
        return;
    }

    jsize tagLength = env->GetArrayLength(tags);
    jint *tagValues = env->GetIntArrayElements(tags, NULL);

    uint8_t buf[LOGGER_ENTRY_MAX_LEN];
    struct timeval timeout = {0, 0};
    fd_set readset;
    FD_ZERO(&readset);

    for (;;) {
        // Use a short select() to try to avoid problems hanging on read().
        // This means we block for 5ms at the end of the log -- oh well.
        timeout.tv_usec = 5000;
        FD_SET(fd, &readset);
        int r = select(fd + 1, &readset, NULL, NULL, &timeout);
        if (r == 0) {
            break;  // no more events
        } else if (r < 0 && errno == EINTR) {
            continue;  // interrupted by signal, try again
        } else if (r < 0) {
            jniThrowIOException(env, errno);  // Will throw on return
            break;
        }

        int len = read(fd, buf, sizeof(buf));
        if (len == 0 || (len < 0 && errno == EAGAIN)) {
            break;  // no more events
        } else if (len < 0 && errno == EINTR) {
            continue;  // interrupted by signal, try again
        } else if (len < 0) {
            jniThrowIOException(env, errno);  // Will throw on return
            break;
        } else if ((size_t) len < sizeof(logger_entry) + sizeof(int32_t)) {
            jniThrowException(env, "java/io/IOException", "Event too short");
            break;
        }
//略
    }
    close(fd);
    env->ReleaseIntArrayElements(tags, tagValues, 0);
}
  评论这张
 
阅读(1961)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017