Неверная ссылка во время обратного вызова

у меня есть объект, который используется для вызова функций обратного вызова:

static jobject o;

я назначил функцию обратного вызова этому объекту через указатель:

o=env->NewGlobalRef(callback);

Тот же указатель env указывает на функцию CallVoidMethod, которая использует JNI для доступа к коду Java.

env->CallVoidMethod(o, methodId, pDeviceId, deviceStatus, statusReason, connectionProgressInfo);

Однако при вызове этой функции происходит сбой системы, и VM говорит, что это недопустимая ссылка на статический объект задания o, а затем происходит сбой.

Мой код выглядит следующим образом:

static jint android_net_wimax_subscribeDeviceStatusChange(JNIE nv* env, jobject clazz, jobject jdeviceId, jobject callback)
{

//  LOGD(" android_net_wimax_subscribeDeviceStatusChange() ->D1");
o = env->NewGlobalRef(callback);
//o = callback;

//   LOGD(" android_net_wimax_subscribeDeviceStatusChange() ->D2");


return (jint)::SubscribeDeviceStatusChange(deviceId, fun_IndDeviceStatusUpdate);
}

void fun_IndDeviceStatusUpdate(WIMAX_API_DEVICE_ID_P pDeviceId, WIMAX_API_DEVICE_STATUS deviceStatus,
WIMAX_API_STATUS_REASON statusReason, WIMAX_API_CONNECTION_PROGRESS_INFO connectionProgressInfo)
{

JNIEnv *env = NULL; 
int nResult = -1; 


//  LOGD(" AttachCurrentThread() ->D1");

nResult = g_jVM->AttachCurrentThread(&env, NULL);

//  LOGD(" AttachCurrentThread() ->D2-%d",nResult);

if ((nResult != 0) || (env == NULL))
{ 
LOGD(" AttachCurrentThread() failed");
} 
else
{
//   LOGD(" AttachCurrentThread() ->D3");


if(o == NULL)
{

LOGD(" o is NULL ");

}
else
{
LOGD(" o is not NULL ");

}

jclass cls = env->GetObjectClass(o);

//   LOGD(" AttachCurrentThread() ->D4");
jmethodID methodId = env->GetMethodID(cls, "callback", "(Landroid/net/wimax/structs/DeviceId;III)V");

//  LOGD(" AttachCurrentThread() failed->D5");
if (methodId) {
env->CallVoidMethod(o, methodId, pDeviceId, deviceStatus, statusReason, connectionProgressInfo);
}

if (g_jVM->DetachCurrentThread() != JNI_OK) {
LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
}
}

//   LOGD("JNI->CALLBACK->D3");

}

‹‹‹ D/wimax ( 1673): перед CallVoidMethod() W/dalvikvm( 1673): ПРЕДУПРЕЖДЕНИЕ JNI: 0x48e31dec не является допустимой ссылкой JNI

W/dalvikvm(1673): в Ldalvik/system/NativeStart;.run ()V (CallVoidMethodV)

I/dalvikvm( 1673): "Thread-55" prio=5 tid=45 RUNNABLE

I/dalvikvm( 1673): | group="main" sCount=0 dsCount=0 s=N obj=0x43b6c930 self=0x306370

I/dalvikvm( 1673): | sysTid=2000 nice=0 sched=0/0 cgrp=неизвестный дескриптор=3194272

Пожалуйста, помогите мне


person dapper    schedule 29.07.2010    source источник


Ответы (2)


Без кода трудно сказать, но я предполагаю, что вы пытаетесь использовать локальную ссылку после того, как функция, в которой она была создана, вернулась на виртуальную машину.

Вы можете получить некоторые базовые советы из документа Android «JNI Tips» в Dalvik docs (см. "Локальные и глобальные ссылки") и более подробную информацию из официальной документации JNI.

person fadden    schedule 29.07.2010
comment
эй, Фадден, я также добавил код. Пожалуйста, посмотрите на это. - person dapper; 30.07.2010
comment
Я все еще этого не вижу. Вы говорите о создании глобальной ссылки на обратный вызов с именем o, но вызов CallVoidMethod, который не работает, не использует ни один из них. Один или несколько параметров pDeviceId, deviceStatus, statusReason или connectionProgressInfo неверны. Добавьте сообщение журнала, которое печатает все четыре в шестнадцатеричном формате (%p) над CallVoidMethod, и посмотрите, какое из них совпадает со значением, показанным в строке JNI WARNING. - person fadden; 31.07.2010
comment
привет, Фадден, я добавил полный исходный код, может быть, теперь у вас есть четкое понимание .. - person dapper; 02.08.2010
comment
У вас есть WIMAX_API_DEVICE_ID_P pDeviceId, но вы передаете его в виртуальную машину, как если бы это был объект задания (первый аргумент метода — это Landroid/net/wimax/structs/DeviceId;). Убедитесь, что он имеет правильный тип и что это глобальная ссылка, если она изначально удерживается между вызовами. - person fadden; 02.08.2010
comment
Но что я получаю, так это то, что ссылка на jobject o в env-›callvoidmethod(o,methodId, pDeviceId, deviceStatus, statusReason, connectionProgressInfo); является недействительным. Что может быть причиной этого? Как я могу это решить. - person dapper; 03.08.2010

Попробуйте использовать pastebin или предварительно отформатированный тег. В fun_IndDeviceStatusUpdate вы ссылаетесь на deviceStatusChangeCB, но я не вижу, где он объявлен или назначен. Вы используете o как статическую глобальную ссылку на обратный вызов. Разве o не должно быть там, где вы ищете класс, а не deviceStatusChangeCB?

Фадден также прав в том, что первым аргументом метода обратного вызова java является экземпляр класса android/net/wimax/structs/DeviceId. Вы уверены, что WIMAX_API_DEVICE_ID_P является экземпляром проекта этого класса? Вы уверены, что сообщение об ошибке (вы можете опубликовать это?) относится к o, а не к аргументу?

Кроме того, вы уверены, что безопасно отсоединить JVM от потока, из которого вызывается этот метод (например, это поток Java)?

person aweisberg    schedule 03.08.2010
comment
aweisberg, я думаю, вы правы, и ошибка только в аргументе. я заменил devicestatusChangeCB на o и добавил журнал ошибок. что вы предлагаете для того, чтобы сделать WIMAX_API_DEVICE_ID экземпляром проекта класса? - person dapper; 04.08.2010
comment
я также получаю следующие сообщения об ошибках: CALBACK -> ppdeviceId= 0x48e31e38 . . . GetMethodID() -> D5 env=0x2C89b0 deviceStatusChangeCB = 0x43b8de08 methodId = 0x412f6620 pdeviceId = 0x48e31e38 DeviceStatus = 5 statusreason=0, connectionprogressinfo=0 D/Wimax 1673 перед CallVoidMethod() W/dalvikvm JNI предупреждение: 0x48e31dec предупреждение: 0x48e31dec /dalvikvm — это Ldalvik/system/NativeStart, run() V (CallVoidMethod V) I/dalvikvm Thread-55 prio=5 tid=45 Runnable D/Wimax 1673 до CallVoidMethod() W/dalvikvm JNI предупреждение: 0x48e31dec не является допустимым JNI ссылка - person dapper; 04.08.2010
comment
Я не знаю, что такое WIMAX_API_DEVICE_ID_P и откуда он взялся. Предполагая, что существует некоторое логическое сопоставление WIMAX_API_DEVICE_ID_P с android/net/wimax/structs/DeviceId, вы можете создать или получить экземпляр android/net/wimax/structs/DeviceId, который соответствует экземпляру WIMAX_API_DEVICE_ID_P, который у вас есть. Вы можете использовать NewObject для создания экземпляра DeviceId и выбора правильного конструктора или, если это вещь типа enum/singleton, вы можете вызывать любые доступные статические методы/геттеры для получения правильного. Кроме того, android/net/wimax/* не является частью Android API. - person aweisberg; 04.08.2010
comment
WIMAX_API_DEVICE_ID_P был определен как статический WIMAX_API_DEVICE_ID_P pdeviceid в каком-то другом связанном файле. Я использовал следующий код для создания экземпляра WIMAX_API_DEVICE_ID_P --- jobject NewObjectV (JNIEnv *env, jclass cls, jmethodID methodId, WIMAX_API_DEVICE_ID_P pDeviceId); но затем я получил следующую ошибку ---- неопределенная ссылка на 'android :: NewObjectV (_JNIEnv *, _jclass *, _jmethod *, _WIMAX_API_DEVICE_ID_P *). я должен использовать NewGlobalRef, чтобы удалить эту ошибку? или есть другой способ для ссылки? - person dapper; 05.08.2010
comment
Это ошибка компилятора? Мне нужно увидеть больше кода, чтобы понять, что вы делаете. статический WIMAX_API_DEVICE_ID_P pdeviceid не является определением. Это объявление хранилища для WIMAX_API_DEVICE_ID_P. Вы уверены, что WIMAX_API_DEVICE_ID_P — это объект Java, который можно создать? jobject NewObjectV (JNIEnv *env, jclass cls, jmethodID methodId, WIMAX_API_DEVICE_ID_P pDeviceId); это прототип функции? - person aweisberg; 05.08.2010
comment
Да, это ошибка компилятора. jobject NewObjectV (JNIEnv *env, jclass cls, jmethodID methodId, WIMAX_API_DEVICE_ID_P pDeviceId); не является прототипом функции. Я использовал этот оператор для создания объекта NewObjectV, а затем использовал его вместо WIMAX_API_DEVICE_ID_P pdeviceId в void fun_IndDeviceStatusUpdate(WIMAX_API_DEVICE_ID_P pDeviceId, WIMAX_API_DEVICE_STATUS deviceStatus, WIMAX_API_STATUS_REASON statusReason...). NewObjectV(_JNIEnv *, _jclass *, _jmethod *, _WIMAX_API_DEVICE_ID_P * ) Какой должен быть код, чтобы избежать этого? - person dapper; 06.08.2010
comment
Мне нужно увидеть весь код на pastebin.com, чтобы понять, что происходит. Это не похоже на правильный вызов метода, потому что он указывает тип возвращаемого значения, а также тип всех аргументов (что делает его прототипом функции). Не похоже, что вы можете создать экземпляр WIMAX_API_DEVICE_ID_P как объект Java (используя env->NewObject), потому что это не ссылка jclass. - person aweisberg; 09.08.2010