#android #segmentation-fault #java-native-interface
#Android #ошибка сегментации #java-родной интерфейс
Вопрос:
В настоящее время я работаю над более крупным проектом с несколькими потоками в собственной среде. Поэтому мне нужен вызов (* vm)-> GetEnv, чтобы получить текущий активный JNIEnv для собственного потока. Потоки подключаются при создании, но я добавил сбой в методе, который вызывает GetEnv:
void get_jni_env(void **e) {
JNIEnv *env = malloc(sizeof(JNIEnv *));
if((*vm)->GetEnv(vm, (void **)amp;env, JNI_VERSION_1_4) != JNI_OK) {
__android_log_write(ANDROID_LOG_ERROR, "Call to GetEnv from a unattached native thread. Trying to attach thread.");
if((*vm)->AttachCurrentThread(vm, amp;env, NULL) != JNI_OK) {
__android_log_write(ANDROID_LOG_ERROR, "Failed to receive any jni environment. Crashing soon");
}
}
*e = env;
}
При пошаговом выполнении вы видите, что вызов (*vm)-> GetEnv segfaults выполняется:
jni_get_long (ctx=0x40525080, key=0x804215e0 "hm") at jni/jni.c:50
50 GET_JNI_ENV(amp;env);
(gdb) s
get_jni_env (e=0xbec603e8) at jni/../../../../core/android/util.c:159
159 if((*vm)->GetEnv(vm, (void **)amp;env, JNI_VERSION_1_4) != JNI_OK) {
(gdb) n
156 void get_jni_env(void **e) {
(gdb)
157 JNIEnv *env = malloc(sizeof(JNIEnv *));
(gdb)
159 if((*vm)->GetEnv(vm, (void **)amp;env, JNI_VERSION_1_4) != JNI_OK) {
(gdb)
Program received signal SIGSEGV, Segmentation fault.
0xaca43510 in ?? () ← this is somewhere on the heap
Тот же код отлично работает на устройствах Samsung и Sony Ericsson, а также в эмуляторе. У меня немного не хватает идей для этой конкретной ошибки. Я также тестировал устройство HTC с CyanogenMod 7.1, которое должно быть довольно похоже на AOSP Android, и даже там оно выходит из строя в тот же момент.
Ответ №1:
Не могу понять, почему вы меняете свою переменную JNIEnv? Android сделает это за вас. В любом случае, вот мой код, который отлично работает на моем HTC Desire:
JNIEnv *GetJEnv() {
JNIEnv *res;
if (jvm->GetEnv((void **)amp;res,JNI_VERSION_1_6)==JNI_EDETACHED)
jvm->AttachCurrentThread(amp;res,NULL);
return res;
}
Комментарии:
1. Ну, это можно игнорировать. Я попытался выяснить, было ли это вызвано некоторыми ошибочными адресами в стеке, и переместил адрес с помощью malloc() в кучу. Но проблема, похоже, в другом месте. Ваша версия тоже не будет работать, я уже пробовал ее заранее. Но спасибо, что нашли время ответить.
Ответ №2:
JNIEnv *env = malloc(sizeof(JNIEnv *));
это неправильно.
Он выделяет память, которая может содержать указатель на JNIEnv
объект, а не объем памяти для JNIEnv
самого объекта.
Это должно быть
JNIEnv *env = malloc(sizeof(JNIEnv));
или даже лучше:
JNIEnv *env = malloc(sizeof( *env ));
«Отлично работает» на других платформах не означает, что это правильно.