【问题标题】:Invalid reference during callback回调期间引用无效
【发布时间】:2010-07-29 13:10:04
【问题描述】:

我有一个用于调用回调函数的对象:

static jobject o;

我已通过指针将回调函数分配给该对象:

o=env->NewGlobalRef(callback);

同一指针env 指向函数CallVoidMethod,该函数使用JNI 访问java 代码。

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

但是在调用这个函数时,系统崩溃了,VM 说它是对静态 jobject 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");

}

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

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

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

我/dalvikvm(1673):| sysTid=2000 nice=0 sched=0/0 cgrp=未知句柄=3194272

请帮帮我

【问题讨论】:

    标签: android callback java-native-interface android-2.2-froyo


    【解决方案1】:

    没有代码看很难说,但我猜你是在创建它的函数返回 VM 后尝试使用本地引用。

    您可以从Dalvik docs 中的 Android“JNI 提示”文档中获得一些基本建议(请参阅“本地与全局参考”),并从官方 JNI 文档中获得更多详细信息。

    【讨论】:

    • 嘿fadden,我也添加了代码。请看一下。
    • 我还是没看到。您谈论为“回调”创建一个名为“o”的全局引用,但是失败的 CallVoidMethod 调用不使用其中任何一个。 “pDeviceId”、“deviceStatus”、“statusReason”或“connectionProgressInfo”中的一项或多项是错误的。添加一条日志消息,在 CallVoidMethod 上方将所有四个打印为十六进制 ("%p"),并查看哪一个与 JNI WARNING 行中显示的值匹配。
    • 嗨fadden,我已经添加了完整的源代码,也许你现在可以清楚地了解了..
    • 您有“WIMAX_API_DEVICE_ID_P pDeviceId”,但您将其传递给 VM,就好像它是一个作业对象(该方法的第一个参数是 Landroid/net/wimax/structs/DeviceId;)。确保它具有正确的类型,并且如果它是跨调用本地保存的,则它是一个全局引用。
    • 但是我得到的是在“ env->callvoidmethod(o,methodId, pDeviceId, deviceStatus, statusReason, connectionProgressInfo); 处对jobject o的引用是无效的。这背后的原因可能是什么?我该如何解决。
    【解决方案2】:

    尝试使用 pastebin 或预先格式化的标签。在 fun_IndDeviceStatusUpdate 中,您引用了 deviceStatusChangeCB,但我看不到它在哪里声明或分配。您使用 o 作为回调的静态全局引用。不应该在您寻找课程的地方而不是 deviceStatusChangeCB 吗?

    Fadden 也是正确的,java 回调方法的第一个参数是类 android/net/wimax/structs/DeviceId 的实例。您确定 WIMAX_API_DEVICE_ID_P 是该类的一个对象实例吗?您确定错误消息(您可以发布吗?)指的是 o 而不是参数?

    另外,您确定将 JVM 从调用此方法的线程中分离是安全的(例如,这是一个 Java 线程)吗?

    【讨论】:

    • aweisberg,我想你是对的,错误仅在论点上。我已将 devicestatusChangeCB 替换为 o 并添加了错误日志。你有什么建议让 WIMAX_API_DEVICE_ID 成为类的对象实例?
    • 我还收到以下错误消息 - CALBACK -> ppdeviceId= 0x48e31e38 。 . . GetMethodID() ->D5 env=0x2C89b0 deviceStatusChangeCB = 0x43b8de08 methodId = 0x412f6620 pdeviceId = 0x48e31e38 DeviceStatus = 5 statusreason=0, connectionprogressinfo=0 D/Wimax 1673 before CallVoidMethod() W/dalvikvm JNI 警告:0x48e31dec 不是有效的 JNI 参考 W /dalvikvm 是 Ldalvik/system/NativeStart, run() V (CallVoidMethod V) I/dalvikvm "Thread-55" prio=5 tid=45 Runnable D/Wimax 1673 before CallVoidMethod() W/dalvikvm JNI 警告:0x48e31dec 不是有效的 JNI 参考
    • 我不知道 WIMAX_API_DEVICE_ID_P 是什么或它来自哪里。假设从 WIMAX_API_DEVICE_ID_P 到 android/net/wimax/structs/DeviceId 存在一些逻辑映射,您可以实例化或检索与您拥有的 WIMAX_API_DEVICE_ID_P 实例相对应的 android/net/wimax/structs/DeviceId 实例。您可以使用 NewObject 实例化 DeviceId 并选择正确的构造函数,或者如果它是枚举/单例类型的事物,您可以调用任何可用的静态方法/getter 来检索正确的构造函数。此外,android/net/wimax/* 不是 Android API 的一部分
    • 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 来消除这个错误吗?还是有其他参考方式?
    • 这是编译器错误吗?我需要查看更多代码以了解您在做什么。 “静态 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);”,是函数原型吗?
    猜你喜欢
    • 2012-06-18
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多