【问题标题】:Android JNI DETECTED ERROR IN APPLICATION: JNI GetMethodID called with pending exceptionAndroid JNI DETECTED ERROR IN APPLICATION: JNI GetMethodID called with pending exception
【发布时间】:2016-01-20 04:34:38
【问题描述】:

我正在尝试使用我的 android 项目运行 Googles OCR Tesseract。我已经将 tesseract 与 android-ndk 兼容,并在尝试运行 android 项目后收到此错误。

我的环境如下

  • Android 5.1.1
  • 适用于 windows 的 android-ndk-r10e
  • android-sdk-r22

作为参考,我从此处列出的示例构建 Example Link

提前致谢!

这是我的 logcat 结果的 sn-p:

  I/DEBUG   (  182): Revision: '0'
    I/DEBUG   (  182): ABI: 'arm'
    I/DEBUG   (  182): pid: 20291, tid: 20337, name: JavaBridge  >>> com.enterprisem
    obility.OCR <<<
    I/DEBUG   (  182): signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    I/DEBUG   (  182): Abort message: 'art/runtime/check_jni.cc:65] JNI DETECTED ERR
    OR IN APPLICATION: JNI GetMethodID called with pending exception 'java.lang.NoSu
    chFieldError' thrown in void com.googlecode.tesseract.android.TessBaseAPI.native
    ClassInit():-2'
    I/DEBUG   (  182):     r0 00000000  r1 00004f71  r2 00000006  r3 00000000
    I/DEBUG   (  182):     r4 a0701db8  r5 00000006  r6 0000000b  r7 0000010c
    I/DEBUG   (  182):     r8 00000000  r9 b486f520  sl a1c0ac00  fp 00000001
    I/DEBUG   (  182):     ip 00004f71  sp a07006d8  lr b6e503c5  pc b6e72f6c  cpsr
    60070010
    I/DEBUG   (  182):
    I/DEBUG   (  182): backtrace:
    I/DEBUG   (  182):     #00 pc 00039f6c  /system/lib/libc.so (tgkill+12)
    I/DEBUG   (  182):     #01 pc 000173c1  /system/lib/libc.so (pthread_kill+52)
    I/DEBUG   (  182):     #02 pc 00017fd3  /system/lib/libc.so (raise+10)
    I/DEBUG   (  182):     #03 pc 00014795  /system/lib/libc.so (__libc_android_abor
    t+36)
    I/DEBUG   (  182):     #04 pc 00012f44  /system/lib/libc.so (abort+4)
    I/DEBUG   (  182):     #05 pc 00228cd7  /system/lib/libart.so (art::Runtime::Abo
    rt()+170)
    I/DEBUG   (  182):     #06 pc 000a7371  /system/lib/libart.so (art::LogMessage::
    ~LogMessage()+1360)
    I/DEBUG   (  182):     #07 pc 000b1b17  /system/lib/libart.so (art::JniAbort(cha
    r const*, char const*)+1118)
    I/DEBUG   (  182):     #08 pc 000b2055  /system/lib/libart.so (art::JniAbortF(ch
    ar const*, char const*, ...)+68)
    I/DEBUG   (  182):     #09 pc 000b530f  /system/lib/libart.so (art::ScopedCheck:
    :ScopedCheck(_JNIEnv*, int, char const*)+1346)
    I/DEBUG   (  182):     #10 pc 000b7755  /system/lib/libart.so (art::CheckJNI::Ge
    tMethodID(_JNIEnv*, _jclass*, char const*, char const*)+36)
    I/DEBUG   (  182):     #11 pc 001332f7  /data/app/com.enterprisemobility.OCR-1/l
    ib/arm/libtess.so (Java_com_googlecode_tesseract_android_TessBaseAPI_nativeClass
    Init+46)
    I/DEBUG   (  182):     #12 pc 0000614d  /data/dalvik-cache/arm/data@app@com.ente
    rprisemobility.OCR-1@base.apk@classes.dex
    W/ActivityManager(  536):   Force finishing activity 1 com.enterprisemobility.OC
    R/.MainActivity
    I/DEBUG   (  182):
    I/DEBUG   (  182): Tombstone written to: /data/tombstones/tombstone_07

【问题讨论】:

    标签: java android android-ndk java-native-interface tesseract


    【解决方案1】:

    Abort 消息 比较清楚:您调用 GetFieldID(cls, fieldName) 获取传递给此函数的类中不存在的字段名称,但您不检查该错误,并且继续调用其他 JNI 函数。不幸的是,您不能忽略此类错误。您必须在调用GetMethodID()大部分 JNI 函数之前调用ExceptionClear()

    您可以使用 addr2line 查找对 getMethodID() 的特定调用崩溃,并据此推导出对 GetFieldID(cls, fieldName) 的调用失败。但我建议在所有 JNI 调用中添加错误检查,因为明天其他一些函数可能会抛出异常。

    【讨论】:

    • 所以我听从了您的建议,并能够追踪错误。它似乎发生在 android-ndk 的 jini.h 文件中。一旦我调用 ExceptionClear(),我必须正确地重建我的 .so 文件?
    • 这样就够了吗? void ExceptionClear(JNIEnv *env) { 函数->ExceptionClear(this); }
    • 我假设您稍后依赖您未能获取的 methodID,因此添加 env->ExceptionClear() 可能还不够。对 C++ 代码的任何更改都需要重新生成 .so 文件。
    【解决方案2】:

    我也遇到了同样的问题,困扰了我2天。最后原因是我传递了错误的对象类型。例如, java代码是

    public OverlayLine(int mWidth,List<GeoPoint> mPoints);
    

    我注册jni方法如下:

    gClass.mInitMethod = env->GetMethodID(gObject, "<init>", "(ILjava/lang/Object;)V");
    

    并在遇到 Errol 时收到错误消息。我修复了代码

    gClass.mInitMethod = env->GetMethodID(gObject, "<init>", "(ILjava/util/List;)V");
    

    并且错误消失了。您应该传递精确的对象类型而不是“Ljava/lang/Object;”。

    【讨论】:

    • 发生这种情况时,它会中断握手,以便 NEXT GetMethodID/GetFieldID 导致系统崩溃。即使那个调用的语法是好的。因此,您需要从它实际停止的位置返回一个 GetMethodID/GetFieldID。 ...在调试代码时重复三次相同的语句很有帮助。好的语句被调用并没有什么坏处,而当它在第二次和第三次调用之间崩溃时,你会知道它实际上是第一次调用错误的语句导致系统崩溃。 ...注意编译器完全可以使用 Ljava/lang/Object; , 运行时错误。
    【解决方案3】:

    你应该使用 android NDK 中的 ndk-stack 工具来找出崩溃的位置。请参阅有关ndk stack 的链接。

    adb logcat > /tmp/foo.txt
    
    $NDK/ndk-stack -sym $PROJECT_PATH/obj/local/armeabi -dump foo.txt
    

    【讨论】:

      【解决方案4】:

      很可能在您的 C++ 代码中错误地定义了 JNI 映射。 JNI 对与 Java 的类型映射有非常严格的约定。例如, 在从 JNI 调用 Java 对象的方法之前,我们需要它的签名。所以方法:

      long myMethod (int n, String s, int[] arr);

      从带有签名的 JNI 中看到:

      (ILJAVA/LANG/STRING;[I])J

      您可以在此处阅读这些规则的非常全面的概述: http://www.rgagnon.com/javadetails/java-0286.html

      【讨论】:

        【解决方案5】:

        调用GetMethodID时遇到类似问题:

        JNI DETECTED ERROR IN APPLICATION: thread Thread[1,tid=15092,Runnable,Thread*=0x791c1b8000,peer=0x7278ab58,"main"] using JNI after critical get
        ...   in call to GetMethodID
        

        在使用 GetMethodID 之前的几个调用

        inBufP = env->GetPrimitiveArrayCritical(jIn, NULL);
        

        解决方案: 我可以通过将 GetPrimitiveArray 更改为 GetByteArrayElements

        来修复本机崩溃
        jboolean isCopy;
        inBufP = env->GetByteArrayElements(jIn, &isCopy);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-05
          相关资源
          最近更新 更多