JNI调用非静态函数段错误 [英] JNI calling non static function segfaults

查看:253
本文介绍了JNI调用非静态函数段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我做Android版SDL库一些工作,但我有一个小的障碍。

此功能在Java定义的:

  / **
 *这个方法是通过SDL使用JNI调用。
 返回:可能为空,但不能为null数组。
 * /
公共静态INT [] inputGetInputDeviceIds(INT源){
    INT [] = IDS InputDevice.getDeviceIds();
    INT [] =过滤新INT [ids.length]
    INT用于= 0;
    的for(int i = 0; I< ids.length ++我){
        的InputDevice设备= InputDevice.getDevice(IDS [I]);
        如果((设备=空)及!及((device.getSources()及!源)= 0)){
            过滤[使用++] = device.getId();
        }
    }
    返回Arrays.copyOf(过滤,使用);
}

在JNI / C端:

  / *返回参数ID找到触摸设备的返回值和ID号* /
INT Android_JNI_GetTouchDeviceIds(INT ** IDS){
    JNIEnv的* ENV = Android_JNI_GetEnv();
    jint来源= 4098; / * == InputDevice.SOURCE_TOUCHSCREEN * /
    jmethodID中期=(* ENV) - > GetStaticMethodID(ENV,mActivityClassinputGetInputDeviceIds,(I)的[Ⅰ);
    jintArray阵列=(jintArray)(* ENV) - GT; CallStaticObjectMethod(ENV,mActivityClass,中,源);
    INT数= 0;
    *的id = NULL;
    如果(阵列){
        数=(INT)(* ENV) - GT; GetArrayLength(ENV,数组);
        如果(0℃,数){
            jint *元素=(* ENV) - GT; GetIntArrayElements(ENV,阵列,NULL);
            如果(元件){
                INT I;
                * IDS = SDL_malloc(*号的sizeof(** IDS));
                对于(I = 0; I&下,数++ⅰ){/ *不假设的sizeof(jint)==的sizeof(int)的* /
                    (* IDS)[我] =元素[I]
                }
                (* ENV) - GT; ReleaseIntArrayElements(ENV,数组元素,JNI_ABORT);
            }
        }
        (* ENV) - GT; DeleteLocalRef(ENV,数组);
    }
    返回数;
}

现在这个工作,但我想编辑此进行呼叫非静态的。我改变了Java端code这样:

 公众诠释[] inputGetInputDeviceIds(INT源){
    INT [] = IDS InputDevice.getDeviceIds();
    INT [] =过滤新INT [ids.length]
    INT用于= 0;
    的for(int i = 0; I< ids.length ++我){
        的InputDevice设备= InputDevice.getDevice(IDS [I]);
        如果((设备=空)及!及((device.getSources()及!源)= 0)){
            过滤[使用++] = device.getId();
        }
    }
    返回Arrays.copyOf(过滤,使用);
}

从函数名称去除静态的。

在JNI的一面我这样做:

  / *返回参数ID找到触摸设备的返回值和ID号* /
INT Android_JNI_GetTouchDeviceIds(INT ** IDS){
    JNIEnv的* ENV = Android_JNI_GetEnv();
    jint来源= 4098; / * == InputDevice.SOURCE_TOUCHSCREEN * /
    // jmethodID中期=(* ENV) - > GetStaticMethodID(ENV,mActivityClassinputGetInputDeviceIds,(I)的[Ⅰ);
    // ------------
    JCLASS clazz所=(* ENV) - GT;的findClass(ENV,组织/ libsdl /应用/ SDLActivity);
    如果(clazz所== 0){
        __android_log_print(ANDROID_LOG_INFO,SDL,查找失败类线SDL_android.c 1409);
        返回;
    }
    jmethodID javamethod =(* ENV) - >的GetMethodID(ENV,clazz所inputGetInputDeviceIds,(I)的[Ⅰ);
    如果(javamethod == 0){
        __android_log_print(ANDROID_LOG_INFO,SDL,发现非静态方法失败SDL_android.c线1414);
        返回;
    }
    __android_log_print(ANDROID_LOG_INFO,SDL,成功,得到JNI方法从ENV SDL_android.c行1416); < - 我顺利到达这条线    jintArray阵列=(* ENV) - GT; CallObjectMethod(ENV,clazz所javamethod,源); < - 这条线段错误
    __android_log_print(ANDROID_LOG_INFO,SDL,去到SDL_android.c行1418);
    如果(阵列)
    {
        __android_log_print(ANDROID_LOG_INFO,SDL,成功,得到阵行1421);
    }
    其他
    {
        __android_log_print(ANDROID_LOG_INFO,SDL,失败抵达阵行1425);
    }
    // ------------
    // jintArray阵列=(jintArray)(* ENV) - GT; CallStaticObjectMethod(ENV,mActivityClass,中,源);
    INT数= 0;
    *的id = NULL;
    如果(阵列){
        数=(INT)(* ENV) - GT; GetArrayLength(ENV,数组);
        如果(0℃,数){
            jint *元素=(* ENV) - GT; GetIntArrayElements(ENV,阵列,NULL);
            如果(元件){
                INT I;
                * IDS = SDL_malloc(*号的sizeof(** IDS));
                对于(I = 0; I&下,数++ⅰ){/ *不假设的sizeof(jint)==的sizeof(int)的* /
                    (* IDS)[我] =元素[I]
                }
                (* ENV) - GT; ReleaseIntArrayElements(ENV,数组元素,JNI_ABORT);
            }
        }
        (* ENV) - GT; DeleteLocalRef(ENV,数组);
    }
    __android_log_print(ANDROID_LOG_INFO,SDL,达到inputGetInputDeviceIds FUNC的终结);
    返回数;
}

这个错误:

  09-19 22:40:53.514:以00000001(code = 1),螺纹29650(线程致命信号11(SIGSEGV):A / libc的(29636) 22463)

我然后重新编译的C库,清理项目,并重新安装应用程序。在该行的code段错误而静态版本是罚款。环视code,有没有其他静态引用这个功能。

这可能是造成该段错误?
我做了一些测试和修改其他静态函数,抓住ENV获取类,查找功能,把它实际工作。

任何想法,为什么这个人会失败?


解决方案

  jintArray阵列=(* ENV) -  GT; CallObjectMethod(ENV,clazz所javamethod,源);
                                                ^^^^^
                                         这是不正确

第二个参数 CallObjectMethod 不应该是一个 JCLASS ,但 jobject 指的是要调用的方法类的实例。结果
所以,你需要在 SDLActivity 实例传递给你的C函数,使C函数可以将它传递给 CallObjectMethod

I am doing some work with the SDL library for android but i'm having a little obstacle.

This function is defined in Java:

/**
 * This method is called by SDL using JNI.
 * @return an array which may be empty but is never null.
 */
public static int[] inputGetInputDeviceIds(int sources) {
    int[] ids = InputDevice.getDeviceIds();
    int[] filtered = new int[ids.length];
    int used = 0;
    for (int i = 0; i < ids.length; ++i) {
        InputDevice device = InputDevice.getDevice(ids[i]);
        if ((device != null) && ((device.getSources() & sources) != 0)) {
            filtered[used++] = device.getId();
        }
    }
    return Arrays.copyOf(filtered, used);
}

on the JNI/C side:

/* returns number of found touch devices as return value and ids in parameter ids */
int Android_JNI_GetTouchDeviceIds(int **ids) {
    JNIEnv *env = Android_JNI_GetEnv();
    jint sources = 4098; /* == InputDevice.SOURCE_TOUCHSCREEN */
    jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "inputGetInputDeviceIds", "(I)[I");
    jintArray array = (jintArray) (*env)->CallStaticObjectMethod(env, mActivityClass, mid, sources);
    int number = 0;
    *ids = NULL;
    if (array) {
        number = (int) (*env)->GetArrayLength(env, array);
        if (0 < number) {
            jint* elements = (*env)->GetIntArrayElements(env, array, NULL);
            if (elements) {
                int i;
                *ids = SDL_malloc(number * sizeof (**ids));
                for (i = 0; i < number; ++i) { /* not assuming sizeof (jint) == sizeof (int) */
                    (*ids)[i] = elements[i];
                }
                (*env)->ReleaseIntArrayElements(env, array, elements, JNI_ABORT);
            }
        }
        (*env)->DeleteLocalRef(env, array);
    }
    return number;
}

Now this works, but I would like to edit this to make the call non static. I changed the Java side code to this:

public int[] inputGetInputDeviceIds(int sources) {
    int[] ids = InputDevice.getDeviceIds();
    int[] filtered = new int[ids.length];
    int used = 0;
    for (int i = 0; i < ids.length; ++i) {
        InputDevice device = InputDevice.getDevice(ids[i]);
        if ((device != null) && ((device.getSources() & sources) != 0)) {
            filtered[used++] = device.getId();
        }
    }
    return Arrays.copyOf(filtered, used);
}

removing the static from the function name.

On the JNI side I do this:

/* returns number of found touch devices as return value and ids in parameter ids */
int Android_JNI_GetTouchDeviceIds(int **ids) {
    JNIEnv *env = Android_JNI_GetEnv();
    jint sources = 4098; /* == InputDevice.SOURCE_TOUCHSCREEN */
    //jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "inputGetInputDeviceIds", "(I)[I");
    //------------
    jclass clazz = (*env)->FindClass(env, "org/libsdl/app/SDLActivity");
    if (clazz == 0) {
        __android_log_print(ANDROID_LOG_INFO, "SDL", "find class failed SDL_android.c line 1409");
        return;
    }
    jmethodID javamethod = (*env)->GetMethodID(env, clazz, "inputGetInputDeviceIds", "(I)[I");
    if (javamethod == 0) {
        __android_log_print(ANDROID_LOG_INFO, "SDL", "find non static method failed SDL_android.c line 1414");
        return;
    }
    __android_log_print(ANDROID_LOG_INFO, "SDL", "SUCCESS GETTING JNI METHOD FROM ENV SDL_android.c line 1416"); <-- i reach this line successfully

    jintArray array = (*env)->CallObjectMethod(env, clazz, javamethod, sources); <-- this line segfaults 
    __android_log_print(ANDROID_LOG_INFO, "SDL", "made it to SDL_android.c line 1418");
    if(array)
    {
        __android_log_print(ANDROID_LOG_INFO, "SDL", "SUCCESS GETTING array line 1421");
    }
    else
    {
        __android_log_print(ANDROID_LOG_INFO, "SDL", "FAILED GETTING array line 1425");
    }
    //------------
    //jintArray array = (jintArray) (*env)->CallStaticObjectMethod(env, mActivityClass, mid, sources);
    int number = 0;
    *ids = NULL;
    if (array) {
        number = (int) (*env)->GetArrayLength(env, array);
        if (0 < number) {
            jint* elements = (*env)->GetIntArrayElements(env, array, NULL);
            if (elements) {
                int i;
                *ids = SDL_malloc(number * sizeof (**ids));
                for (i = 0; i < number; ++i) { /* not assuming sizeof (jint) == sizeof (int) */
                    (*ids)[i] = elements[i];
                }
                (*env)->ReleaseIntArrayElements(env, array, elements, JNI_ABORT);
            }
        }
        (*env)->DeleteLocalRef(env, array);
    }
    __android_log_print(ANDROID_LOG_INFO, "SDL", "reached the end of inputGetInputDeviceIds func");
    return number;
}

with this error:

09-19 22:40:53.514: A/libc(29636): Fatal signal 11 (SIGSEGV) at 0x00000001 (code=1), thread 29650 (Thread-22463)

I then recompile the c libs, clean the project and reinstall the app. The code segfaults at that line while the static version is fine. From looking around the code, there's no other static references in this function.

What could be causing that segfault? I've done a few tests and changing other static functions, grabbing the env getting the class, looking up the function and calling it actually works.

Any idea why this one will fail?

解决方案

jintArray array = (*env)->CallObjectMethod(env, clazz, javamethod, sources);
                                                ^^^^^   
                                         This is incorrect

The second argument to CallObjectMethod shouldn't be a jclass, but a jobject refering to the instance of that class that you want to invoke the method on.
So you'll need to pass the SDLActivity instance to your C function, so that the C function can pass it to CallObjectMethod.

这篇关于JNI调用非静态函数段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆