如何在JNI中抛异常

Posted 古月书斋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在JNI中抛异常相关的知识,希望对你有一定的参考价值。

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文件中进行的。查看源码你会发现 jniThrowNullPointerException jniThrowRuntimeException jniThrowIOException 其实就是个特殊的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);

以上是关于如何在JNI中抛异常的主要内容,如果未能解决你的问题,请参考以下文章

为什么在JNI中调用光纤会在JVM中抛出StackOverflow?

使用挂起异常java.lang.ClassNotFoundException调用JNI GetMethodID

如何在扩展中抛出异常?

如何在 C 中抛出异常?

如何在 Symfony2 中抛出 403 异常?

如何捕获ctypes中抛出的异常?