JNI 调用非静态函数段错误

JNI calling non static function segfaults

我正在为 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 库,清理项目并重新安装应用程序。该行的代码段错误,而静态版本很好。通过查看代码,此函数中没有其他静态引用。

是什么导致了该段错误? 我已经完成了一些测试并更改了其他静态函数,获取了获得 class 的环境,查找该函数并调用它确实有效。

知道为什么这个会失败吗?

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

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