JNI DETECTED ClassNotFoundException - 但类在.apk / .dex中可见?

时间:2018-01-30 02:12:53

标签: java android android-ndk

我遇到了一个我无法解决的问题。

首先,我在Ubuntu 14.04上为Android编译了openFrameworks androidVideoExample(我在命令行使用了gradlew assembleDebug);然后,使用adb install ./build/outputs/apk/androidVideoExample-debug.apk在Android设备上部署生成的.apk。我已经部署在Android 4.2.2设备和Android 6.0.1设备上 - 它可以在两者上运行而不会崩溃。

然后,我尝试在我的测试应用程序(myApp)的代码中使用该示例中使用的视频组件openFrameworks ofVideoPlayer,该代码之前已在这些设备上构建并运行良好。当我构建它时 - 再次使用gradlew assembleDebug - 它构建正常,并且在两个设备上使用adb install ./build/outputs/apk/myApp-debug.apk安装也很好。但是,当我运行它时,它会在两台设备上启动时崩溃。

所以,我用adb logcat进行了检查 - 4.2.2设备没有给我一个有用的跟踪;然而,6.0.1最终有类似的东西:

--------- beginning of crash
01-29 23:56:22.551  8938  8973 F libc    : Fatal signal 6 (SIGABRT), code -6 in tid 8973 (Thread-21892)
01-29 23:56:22.653   383   383 D clmlib  : Got activities:0x0000000E
01-29 23:56:22.654   383   383 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-29 23:56:22.654   383   383 F DEBUG   : UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
01-29 23:56:22.655   383   383 F DEBUG   : Build fingerprint: 'XXXXXXXXXXXXXXX:user/release-keys'
01-29 23:56:22.655   383   383 F DEBUG   : Revision: '0'
01-29 23:56:22.655   383   383 F DEBUG   : ABI: 'arm'
01-29 23:56:22.655   383   383 F DEBUG   : pid: 8938, tid: 8973, name: Thread-21892  >>> cc.openframeworks.myApp <<<
01-29 23:56:22.655   383   383 F DEBUG   : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
01-29 23:56:22.694   383   383 F DEBUG   : Abort message: 'art/runtime/java_vm_ext.cc:410] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception java.lang.ClassNotFoundException: Didn't find class "cc.openframeworks.OFAndroidVideoPlayer" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]'
01-29 23:56:22.694   383   383 F DEBUG   :     r0 00000000  r1 0000230d  r2 00000006  r3 967e6978
01-29 23:56:22.694   383   383 F DEBUG   :     r4 967e6980  r5 967e6930  r6 0000000b  r7 0000010c
...

首先,请注意这些关于这些视频对象关系的grep片段:

openFrameworks/libs/openFrameworks/video/ofVideoPlayer.h:   #include "ofxAndroidVideoPlayer.h"

openFrameworks/addons/ofxAndroid/src/ofxAndroidVideoPlayer.cpp: jclass localClass = env->FindClass("cc/openframeworks/OFAndroidVideoPlayer");

openFrameworks/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoPlayer.java:public class OFAndroidVideoPlayer extends OFAndroidObject implements OnFrameAvailableListener {

好的,所以我认为消息'没有找到课程“cc.openframeworks.OFAndroidVideoPlayer”'意味着我从我的.apk中错过了某些课程;但是,我试过这个:

$ zipgrep OFAndroidVideoPlayer /path/to/build/outputs/apk/myApp-debug.apk
classes.dex:Binary file (standard input) matches
lib/armeabi-v7a/libOFAndroidApp.so:Binary file (standard input) matches
好吧,看起来他们在那里?尝试看得更近,也使用dexdump

$ cd /tmp
$ mkdir unpack
$ cd unpack
$ unzip /path/to/build/outputs/apk/myApp-debug.apk
$ /path/to/sdk/build-tools/19.1.0/dexdump ./classes.dex | grep OFAndroidVideoPlayer
  Class descriptor  : 'Lcc/openframeworks/OFAndroidVideoPlayer$1;'
    #0              : (in Lcc/openframeworks/OFAndroidVideoPlayer$1;)
      type          : 'Lcc/openframeworks/OFAndroidVideoPlayer;'
    #0              : (in Lcc/openframeworks/OFAndroidVideoPlayer$1;)
      type          : '(Lcc/openframeworks/OFAndroidVideoPlayer;)V'
        0x0000 - 0x0006 reg=0 this Lcc/openframeworks/OFAndroidVideoPlayer$1;
    #0              : (in Lcc/openframeworks/OFAndroidVideoPlayer$1;)
        0x0000 - 0x0025 reg=2 this Lcc/openframeworks/OFAndroidVideoPlayer$1;
  source_file_idx   : 358 (OFAndroidVideoPlayer.java)
  Class descriptor  : 'Lcc/openframeworks/OFAndroidVideoPlayer$2;'
    #0              : (in Lcc/openframeworks/OFAndroidVideoPlayer$2;)
      type          : 'Lcc/openframeworks/OFAndroidVideoPlayer;'
    #0              : (in Lcc/openframeworks/OFAndroidVideoPlayer$2;)
      type          : '(Lcc/openframeworks/OFAndroidVideoPlayer;)V'
        0x0000 - 0x0006 reg=0 this Lcc/openframeworks/OFAndroidVideoPlayer$2;
    #0              : (in Lcc/openframeworks/OFAndroidVideoPlayer$2;)
        0x0000 - 0x0001 reg=0 this Lcc/openframeworks/OFAndroidVideoPlayer$2;
  source_file_idx   : 358 (OFAndroidVideoPlayer.java)
  Class descriptor  : 'Lcc/openframeworks/OFAndroidVideoPlayer$3;'
    #0              : (in Lcc/openframeworks/OFAndroidVideoPlayer$3;)
      type          : 'Lcc/openframeworks/OFAndroidVideoPlayer;'
    #0              : (in Lcc/openframeworks/OFAndroidVideoPlayer$3;)
      type          : '(Lcc/openframeworks/OFAndroidVideoPlayer;)V'
        0x0000 - 0x0006 reg=0 this Lcc/openframeworks/OFAndroidVideoPlayer$3;
    #0              : (in Lcc/openframeworks/OFAndroidVideoPlayer$3;)
        0x0000 - 0x0007 reg=2 this Lcc/openframeworks/OFAndroidVideoPlayer$3;
  source_file_idx   : 358 (OFAndroidVideoPlayer.java)
...
    #28              : (in Lcc/openframeworks/OFAndroidVideoPlayer;)
        0x0000 - 0x001d reg=2 this Lcc/openframeworks/OFAndroidVideoPlayer;
  source_file_idx   : 358 (OFAndroidVideoPlayer.java)

嗯 - 至少这表示cc/openframeworks/OFAndroidVideoPlayer位于我classes.dex的{​​{1}}中 - 所以这应该意味着班级在那里?事实上,.apkdexdump ./classes.dex ... | grep OFAndroidVideoPlayer的{​​{1}}输出相同!

我还尝试了dex-method-counts,并且对于myApp-debug.apk“总方法计数:710”,因此远远低于需要multidex的65536限制。

否则,这些类由openFrameworks在这里编译:

androidVideoExample-debug.apk

所以,4个用于调试的java类和4个用于发布的java类 - 我猜测这些类最终会出现在myApp-debug.apk中。

最后,我开始以二进制模式在这些项目的源文件夹中进行grepping,希望找到差异:

$ find /path/to/openFrameworks/ -name '*AndroidVideoPla*'
...
/path/to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/debug/cc/openframeworks/OFAndroidVideoPlayer$3.class
/path/to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/debug/cc/openframeworks/OFAndroidVideoPlayer.class
/path/to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/debug/cc/openframeworks/OFAndroidVideoPlayer$2.class
/path/to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/debug/cc/openframeworks/OFAndroidVideoPlayer$1.class
/path/to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/release/cc/openframeworks/OFAndroidVideoPlayer$3.class
/path/to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/release/cc/openframeworks/OFAndroidVideoPlayer.class
/path/to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/release/cc/openframeworks/OFAndroidVideoPlayer$2.class
/path/to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/release/cc/openframeworks/OFAndroidVideoPlayer$1.class

...我将这些输出与classes.dex进行了比较。我唯一能找到的是,grep -rao .......OFAndroidVideoPlayer...... . | tr -cd '\11\12\40-\176' > /tmp/a2 源文件夹将这些作为重复条目:

meld

现在这些都是myApp ./.gradle/2.4/taskArtifacts/fileSnapshots.bin: /to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/release/cc/openframeworks/OFAndroidVideoPlayer.class ./.gradle/2.4/taskArtifacts/fileSnapshots.bin: /to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/release/cc/openframeworks/OFAndroidVideoPlayer$1.cla ./.gradle/2.4/taskArtifacts/fileSnapshots.bin: /to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/release/cc/openframeworks/OFAndroidVideoPlayer$3.cla ./.gradle/2.4/taskArtifacts/fileSnapshots.bin: /to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/release/cc/openframeworks/OFAndroidVideoPlayer$2.cla ./.gradle/2.4/taskArtifacts/fileSnapshots.bin: /to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/debug/cc/openframeworks/OFAndroidVideoPlayer.class ./.gradle/2.4/taskArtifacts/fileSnapshots.bin: /to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/debug/cc/openframeworks/OFAndroidVideoPlayer$2.cla ./.gradle/2.4/taskArtifacts/fileSnapshots.bin: /to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/debug/cc/openframeworks/OFAndroidVideoPlayer$3.cla ./.gradle/2.4/taskArtifacts/fileSnapshots.bin: /to/openFrameworks/addons/ofxAndroid/ofAndroidLib/build/intermediates/classes/debug/cc/openframeworks/OFAndroidVideoPlayer$1.cla 中的重复项 - 而不是gradlew本身 - 所以我不会遇到重复的类错误(比如说,{ {3}})。此外,除了两个项目中fileSnapshots.bin.apk的现有条目外,这些还是重复的。然后我只是删除了OFAndroidVideoPlayer目录的内容:

fileSnapshots.bin

...然后我.gradle/2.4/taskArtifacts/再次重建rm -rfv .gradle/2.4/taskArtifacts/* - 这次,gradlew assembleDebug中没有重复项(myApp {{1} } fileSnapshots.binmyApp的引用数相同。但是,应用程序在启动时仍会崩溃,但错误完全相同。

所以,据我所知,fileSnapshots.bin OFAndroidVideoPlayer androidVideoExampleOFAndroidVideoPlayer的{​​{1}}类,但是JNI仍然无法在运行时看到它们,在应用程序启动时?可能是什么原因 - 我怎么能进一步调试呢?

例如,我还有哪些方法可以比较工作.dex和崩溃.apk之间在“缺少”myApp Java类方面的差异?

1 个答案:

答案 0 :(得分:0)

请注意搜索路径中没有dex文件:

...on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]'

通常,当有人附加一些以本机启动的线程然后尝试加载Java类时,会发生这种情况。这些线程的默认类加载器并不知道你的dex。您可以尝试从最初在java中创建的任何线程执行该查找。从JNI_OnLoad()执行此操作将非常理想。