JNI调用非静态函数段错误

时间:2015-09-19 15:12:51

标签: android c android-ndk java-native-interface sdl-2

我正在为Android安装SDL库,但我有一点障碍。

此函数在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);
}

在JNI / C方面:

/* 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;
}

现在这样可行,但我想编辑它以使调用非静态。我将Java端代码更改为:

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);
}

从函数名中删除静态。

在JNI方面,我这样做:

/* 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;
}

出现此错误:

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

然后我重新编译c libs,清理项目并重新安装应用程序。代码段错误在那一行,而静态版本没问题。通过查看代码,此函数中没有其他静态引用。

可能导致该段错误的原因是什么? 我做了一些测试并更改了其他静态函数,抓住了获取类的env,查找函数并调用它实际上有效。

知道为什么这会失败?

1 个答案:

答案 0 :(得分:2)

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

CallObjectMethod的第二个参数不应该是jclass,而是jobject引用要调用该方法的该类的实例。
因此,您需要将SDLActivity实例传递给C函数,以便C函数可以将其传递给CallObjectMethod