NDK开发之错误集锦

1、  JNI DETECTED ERROR IN APPLICATION: native code passing in reference to invalid local reference: 0x21

in call to CallVoidMethod  

原来的代码如下:

extern JNIEnv* jniEnv;

jclass TestProvider;

jobject mTestProvider;

jmethodID getTime;

jmethodID sayHello;

int InitProvider(){

    if(jniEnv == NULL){

            return 0;

    }

    if(TestProvider == NULL){

            TestProvider = (*jniEnv) -> FindClass(jniEnv,"ruoki/com/jnipractice3/TestProvider");

            if(TestProvider == NULL){

                  return -1;

            }

    }

    if(mTestProvider == NULL){

            if(GetProviderInstance(TestProvider) !=1){

                    (*jniEnv) -> DeleteLocalRef(jniEnv,TestProvider);

                    return -1;

              }

    }

    if(getTime == NULL){

            getTime = (*jniEnv) ->GetStaticMethodID(jniEnv,TestProvider,"getTime","()Ljava/lang/String;");

            if(getTime == NULL){

                    (*jniEnv) -> DeleteLocalRef(jniEnv,TestProvider);

                    (*jniEnv) -> DeleteLocalRef(jniEnv,mTestProvider);

                    return -2;

            }

    }

    if(sayHello == NULL){

            sayHello = (*jniEnv) -> GetMethodID(jniEnv,TestProvider,"sayHello","(Ljava/lang/String;)V");

            if(sayHello == NULL){

                    (*jniEnv) -> DeleteLocalRef(jniEnv,TestProvider);

                    (*jniEnv) -> DeleteLocalRef(jniEnv,mTestProvider);

                    (*jniEnv) -> DeleteLocalRef(jniEnv,getTime);

                    return -3;

            }

    }

    return 1;

}

int GetProviderInstance(jclass obj_class){

    if(obj_class == NULL){

        return 0;

    }

    //默认构造函数,不传参数

    jmethodID construction_id = (*jniEnv) -> GetMethodID(jniEnv,obj_class,"","()V");

    if(construction_id ==0){

        return -1;

    }

    //通过NewObject来创建对象

    mTestProvider  = (*jniEnv) -> NewObject(jniEnv,obj_class,construction_id);

    if( mTestProvider  == NULL){

        return -2;

    }

    return 1;

}

void GetTime(){

        if(TestProvider == NULL || getTime == NULL){

                int result = InitProvider();

                if(result !=1){

                        return;

         }

        jstring jstr = NULL;

        char* cstr = NULL;

        jstr = (*jniEnv) -> CallStaticObjectMethod(jniEnv,TestProvider,getTime);

        cstr = (char*)(*jniEnv) -> GetStringUTFChars(jniEnv,jstr,0);

        (*jniEnv) -> ReleaseStringUTFChars(jniEnv,jstr,cstr);

        (*jniEnv) -> DeleteLocalRef(jniEnv,jstr);

}

void SayHello(){

        if(TestProvider == NULL || mTestProvider == NULL || sayHello == NULL){

                int result = InitProvider();

                if(result !=1){

                        return;

                }

        }

        jstring jstrMSG = NULL;

        jstrMSG = (*jniEnv) -> NewStringUTF(jniEnv,"Hi,I'm From C");

        (*jniEnv) -> CallVoidMethod(jniEnv,mTestProvider,sayHello,jstrMSG);

        (*jniEnv) -> DeleteLocalRef(jniEnv,jstrMSG);

}

其中GetTime和sayHello由Java调用:

void Java_ruoki_com_jnipractice3_MainActivity_getTime(JNIEnv* env,jobject obj){

        if(jniEnv == NULL){

                jniEnv = env;

        }

        GetTime();

}

void Java_ruoki_com_jnipractice3_MainActivity_sayHello(JNIEnv* env,jobject obj){

        if(jniEnv == NULL){

                jniEnv = env;

         }

        SayHello();

}

这么写最终导致不管是调用GetTime还是SayHello,调用第二次程序直接crash,日志如下:

JNI DETECTED ERROR IN APPLICATION: native code passing in reference to invalid local reference: 0x21

in call to CallVoidMethod  

JNI DETECTED ERROR IN APPLICATION: jclass is an invalid local reference: 0x20001d (0xdead4321) in call to CallStaticObjectMethod

JNI DETECTED ERROR IN APPLICATION: use of deleted local reference 0x19

    这个错误显示是CallVoidMethod的参数非法引用,网上找了一些相关问题的帖子,结合本地代码,发现最有可能的就是线程间不能直接传递JNIEnv和jobject这类线程专属属性值导致,要知道JavaVM是属于java进程的,每个进程只有一个JavaVM,而这个JavaVM可以被多线程共享,但是JNIEnv和jobject是属于线程私有的,不能共享,所以:局部引用只在创建它们的线程中有效,跨线程使用是被禁止的。不要在一个线程中创建局部引用并存储到全局引用中,然后到另外一个线程去使用!

这里,我们将上面加粗的代码替换成以下的代码即可:

创建TestProvider 全局引用:


jclass tmpTestProvider = (*jniEnv) -> FindClass(jniEnv,"ruoki/com/jnipractice3/TestProvider");

if(tmpTestProvider == NULL){

return -1;

}

TestProvider = (jclass)(*jniEnv)->NewGlobalRef(jniEnv,tmpTestProvider);

(*jniEnv) -> DeleteLocalRef(jniEnv,tmpTestProvider);

创建mTestProvider 全局引用:

jobject tempTestProviderObject = (*jniEnv) -> NewObject(jniEnv,obj_class,construction_id);

if(tempTestProviderObject == NULL){

return -2;

}

mTestProvider = (jobject)(*jniEnv)->NewGlobalRef(jniEnv,tempTestProviderObject);

(*jniEnv) -> DeleteLocalRef(jniEnv,tempTestProviderObject);

后记:

其实有点不懂:为什么getTime和sayHello这两个引用没有问题呢?由于刚学习jni,菜鸟一枚,如有大神路过,烦请解疑,不胜感激!

2、comparison of array 'num' equal to a null pointer is always false

错误日志为:


解决方案:

将一下语句

if(num == NULL){ return NULL; }

换成:

if(num[0] =='\0'){

return NULL;

}

即可。

你可能感兴趣的:(NDK开发之错误集锦)