文章目录

先看一下异常信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
JNI WARNING: JNI function NewGlobalRef called with exception pending
in Ljava/lang/Class;.getDex:()Lcom/android/dex/Dex; (NewGlobalRef)
Pending exception is:
java.lang.IndexOutOfBoundsException: index=0, limit=0
at java.nio.Buffer.checkIndex(Buffer.java:156)
at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:157)
at com.android.dex.Dex.create(Dex.java:129)
at java.lang.Class.getDex(Native Method)
at libcore.reflect.AnnotationAccess.getSignature(AnnotationAccess.java:447)
at java.lang.Class.getTypeParameters(Class.java:1070)
05-11 15:14:28.285: I/dalvikvm(8083): at android.app.Activity.performCreate(Activity.java:5248)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
at android.app.ActivityThread.access$800(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5086)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
"main" prio=5 tid=1 NATIVE
| group="main" sCount=0 dsCount=0 obj=0x416b6e40 self=0x415d8500
| sysTid=8083 nice=0 sched=0/0 cgrp=apps handle=1074389332
| state=R schedstat=( 0 0 0 ) utm=13 stm=4 core=3
#00 pc 0000132e /system/lib/libcorkscrew.so (unwind_backtrace_thread+29)
#01 pc 000635ba /system/lib/libdvm.so (dvmDumpNativeStack(DebugOutputTarget const*, int)+33)
#02 pc 00057590 /system/lib/libdvm.so (dvmDumpThreadEx(DebugOutputTarget const*, Thread*, bool)+395)
#03 pc 000575fe /system/lib/libdvm.so (dvmDumpThread(Thread*, bool)+25)
#04 pc 0003b554 /system/lib/libdvm.so
#05 pc 00043f2c /system/lib/libdvm.so
#06 pc 0006a4ea /system/lib/libdvm.so (Java_java_lang_Class_getDex(_JNIEnv*, _jclass*)+141)
#07 pc 000203cc /system/lib/libdvm.so (dvmPlatformInvoke+112)
#08 pc 00050eea /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+397)
#09 pc 00029860 /system/lib/libdvm.so
#10 pc 00030b68 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
#11 pc 0002e200 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
#12 pc 000637cc /system/lib/libdvm.so (dvmInvokeMethod(Object*, Method const*, ArrayObject*, ArrayObject*, ClassObject*, bool)+391)
#13 pc 0006b6aa /system/lib/libdvm.so
#14 pc 00029860 /system/lib/libdvm.so
#15 pc 00030b68 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
#16 pc 0002e200 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
#17 pc 000634e8 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+335)
#18 pc 0004cab6 /system/lib/libdvm.so
#19 pc 0004d5c0 /system/lib/libandroid_runtime.so
#20 pc 0004e2e6 /system/lib/libandroid_runtime.so (android::AndroidRuntime::start(char const*, char const*)+353)
#21 pc 0000105a /system/bin/app_process
#22 pc 0000e510 /system/lib/libc.so (__libc_init+47)

很明显,是因为应用调用了 java.lang.Class.getTypeParameters()方法导致的问题,这个方法是用来获取泛型数量,在GSON或fastjson这样的第三方JSON反射框架中会出现这样的调用,出现这样的问题也正是使用这样的类库出现的。为什么只会在android4.4系统中出现这样的兼容性问题,而其他版本没有?从堆栈错误信息中可以看出来,在Java层最后调用的一个方法是Class.getDex(),这个是个native方法,只在C++代码中实现,而android其他版本却没有这个方法。查看dalvik/vm/native/java_lang_Class.cpp中的JNIEXPORT jobject JNICALL Java_java_lang_Class_getDex(JNIEnv* env, jclass javaClass)函数发现,在NDK中new一个Dex对象,而在这个对象时传的参数为空,导致在java层通过下标访问时出现了java.lang.IndexOutOfBoundsException异常,这也解释了为什么会出现NewGlobalRef pending exception。最后在源码中插入LOG,编译验证了一下,证明确实是这样。

OK,问题产生的原因找到了,怎么解决呢?

应用加载DEX文件时,调用了4.4新增了static void Dalvik_dalvik_system_DexFile_openDexFile_bytearray(const u4 args, JValue pResult)函数,直接将一个DEX文件的字节流传入,虚拟机自动解析并加载类相关信息。虽然这个函数是static,但因为使用到了NDK注册的方式,将Java层的方法与C++层对应的函数绑定到了一起,这样就可以使用指针遍历dvm_dalvik_system_DexFile数组找到对应的函数指针,从而可以调用。而在Java层的DexFile类中没有找到与之对应的int openDexFile(byte)方法,估计是被删了,而这个函数又没有被google官方验证,所以种种巧合,掉进了这个坑。唉,不说了,都是泪啊。

最后问题还是解决了,根本原因是RawDexFile->pDvmDex->memMap指针为空,分配内存赋值就O了。

文章目录