I've run into a problem that I really cannot wrap my head around.
First, I compiled the openFrameworks androidVideoExample for Android on Ubuntu 14.04 (I used gradlew assembleDebug
on the command line for that); and then, deployed the resulting .apk on Android device using adb install ./build/outputs/apk/androidVideoExample-debug.apk
. I've deployed on Android 4.2.2 device, and Android 6.0.1 device - it works on both without crashing.
Then, I tried using the video component used in that example, the openFrameworks ofVideoPlayer, in a code for my test app (myApp
), which previously built and ran fine on either of these devices. When I built it - again with gradlew assembleDebug
- it builds fine, and also installs fine using adb install ./build/outputs/apk/myApp-debug.apk
on both devices. However, when I run it, it crashes on startup on both devices.
So, I inspected with adb logcat
- the 4.2.2 device does not give me a useful trace; however, the 6.0.1 eventually has something like this:
--------- 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
...
First, note these grep snippets about the relationships of these video objects:
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 {
Ok, so I thought the message 'Didn't find class "cc.openframeworks.OFAndroidVideoPlayer"' means I'm missing the classes somehow from my .apk; however, I tried this:
$ 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
Well, looks like they are there? Tried looking a bit closer, also using 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)
Well - at least this says cc/openframeworks/OFAndroidVideoPlayer
is in classes.dex
, which is in my .apk
- so that should mean that the class is there? And in fact, the dexdump ./classes.dex ... | grep OFAndroidVideoPlayer
output is identical for myApp-debug.apk
and for androidVideoExample-debug.apk
!
I also tried dex-method-counts, and for myApp-debug.apk
"Overall method count: 710", and so it is far below the 65536 limit which would require multidex.
Otherwise, these classes are compiled by openFrameworks here:
$ 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
So, 4 java classes for debug, and 4 java classes for release - I'm guessing these are the ones that end up in classes.dex
.
Finally, I started grepping in the source folders of these projects in binary mode, hoping to find a difference:
grep -rao .......OFAndroidVideoPlayer...... . | tr -cd '\11\12\40-\176' > /tmp/a2
... and I compared these outputs with meld
. The only thing I could find, was that the myApp
source folder had these as duplicate entries:
./.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
Now these are duplicates in gradlew
's fileSnapshots.bin
- not in the .apk
per se - and so I don't get duplicate class errors (which they get, say, here). And also, these were duplicates in addition to the already existing entries for OFAndroidVideoPlayer
in fileSnapshots.bin
in both projects. Then I just simply deleted the contents of .gradle/2.4/taskArtifacts/
directory:
rm -rfv .gradle/2.4/taskArtifacts/*
... and then I did gradlew assembleDebug
to rebuild myApp
again - and this time, no duplicates were present in fileSnapshots.bin
(so myApp
's fileSnapshots.bin
had the same number of references to OFAndroidVideoPlayer
as the androidVideoExample
). However, the app still crashes on startup, with the exactly same error.
So, as far as I can see, the OFAndroidVideoPlayer
classes are there in the .dex
in the .apk
for myApp
- but JNI still cannot see them at runtime, during application startup? What could possibly be the reason for this - and how could I debug this further?
For instance, what other ways I have to compare the differences between the working androidVideoExample
, and the crashing myApp
, in respect to the "missing" cc.openframeworks.OFAndroidVideoPlayer
Java Class ?
Notice that there is no dex files in search path:
...on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]'
Typically this occurs when someone attaches some thread started in native and then tries to load Java classes. Default class loader for such threads doesn't know about your dex'es. You may try to perform that lookup from any thread that was initially created in java. Doing this from JNI_OnLoad()
would be ideal.
User contributions licensed under CC BY-SA 3.0