Есть ли способ заставить Java VM немедленно выполнить исключение, отправленное из JNI? - PullRequest
4 голосов
/ 01 ноября 2019

Мне нужно отправить исключение в Java из основного jni-потока. Для этого я использую следующий код:

if (vm->AttachCurrentThread(reinterpret_cast<void **>(&env), nullptr) != JNI_OK || env == nullptr) {
    std::cerr << "Get env for current thread failed.\n";
    return ;
}
jclass exClass = env->FindClass("[JavaClassName]");
if (exClass != nullptr) {
    env->ThrowNew(exClass, "[ExceptionMessage]");
}
env->DeleteLocalRef(exClass);
vm->DetachCurrentThread();

Это как-то работает. Я обнаружил, что если мы не используем присоединение и отсоединение (просто используем только бросок), то исключение возникает только после завершения вызова jni из Java VM. Если мы используем присоединение и отсоединение, то исключение возникает в вызове отсоединения. Это правильный способ сделать вещи быстрее? Я до сих пор не понимаю, почему обработка исключений откладывается до вызова DetachCurrentThread ()? Я использую Android. Большое спасибо.

1 Ответ

3 голосов
/ 01 ноября 2019

Интерпретатор Java, подключенный к вашему текущему потоку, не работает, пока вы находитесь в коде JNI. Таким образом, нет способа обработать исключение на стороне Java (развернуть кадры стека, перехватить и т. Д.). Исключение Java создается как ожидающее и действительно генерируется, только когда вызов JNI возвращается в Java, и выполнение интерпретатора продолжается для вашего текущего потока Java.

Отключение подобного процесса подделывает этот процесс, но может оставить ваш код JNI внестабильное состояние: Java теперь работает, JNI не вернулся и все еще выполняет ваш код.

Мое предпочтительное решение - генерировать исключение Java, как вы делаете, и немедленно генерировать исключение C ++, которое является единственным (и должнобыть) пойман на границе JNI и сброшен. Исключение C ++ вызывается исключительно для того, чтобы вызвать раскручивание стека и быстрый чистый выход из вызова JNI.

...