Android2.2,2.3,2.3.3都存在的一个bug,在这里有详细的描述。 http://code.google.com/p/android/issues/detail?id=12987 其中,楼主的代码可以下来运行一下,我在2.2和2.3模拟器和2.3的真机上都存在这个问题。 问题的核心在于这样一句话:JNI WARNING: jarray 0x4074f6e0 points to non-array object (Ljava/lang/String;) 也就是进行JNI调用时,把一个Java中的String对象当数组来访问了,最终导致虚拟机崩溃。
先是看到这里(http://code.google.com/p/android/issues/detail?id=12987)有人提到,Google的Nexus S因为使用了V8引擎所以不存在这个问题,就把我们系统中的JS引擎由JSC改为V8(具体过程参考这里http://blog.csdn.net/a345017062/archive/2011/04/20/6336753.aspx),发现问题依然存在。没办法只能一步一步地跟踪了。
对这个问题进行跟踪时,费了很大的劲,所以先记录一下跟踪过程。 一开始,想着系统有自己的JNI调用跟踪系统,就使用系统的吧(具体过程这里有http://blog.csdn.net/a345017062/archive/2011/04/28/6369535.aspx),等我把编译好的.so库升级到板子上,查看LOG直接傻眼了,没用的东西太多了,只能自己打印LOG了。
一共使用了两个方法,一个是根据下面这段VM崩溃时系统打印的LOG中提到的抛出异常的本地方法,找出最终调用哪个函数时出现了问题。一开始沿着这个思路走,走得很艰难。因为JavaScriptCore中某些代码无法使用LOGW等一系列方法,最后参考了一篇文章(这里有详细的描述http://blog.csdn.net/a345017062/archive/2011/05/04/6394897.aspx)才让LOG出来
12-20 19:29:34.582: WARN/dalvikvm(725): JNI WARNING: jarray 0x4074f6e0 points to non-array object (Ljava/lang/String;) 12-20 19:29:34.622: INFO/dalvikvm(725): "WebViewCoreThread" prio=5 tid=9 NATIVE 12-20 19:29:34.622: INFO/dalvikvm(725): | group="main" sCount=0 dsCount=0 obj=0x40521328 self=0x26bea8 12-20 19:29:34.622: INFO/dalvikvm(725): | sysTid=734 nice=0 sched=0/0 cgrp=default handle=2539488 12-20 19:29:34.632: INFO/dalvikvm(725): | schedstat=( 5341953614 5808331660 581 ) 12-20 19:29:34.632: INFO/dalvikvm(725): at android.webkit.WebViewCore.nativeTouchUp(Native Method) 12-20 19:29:34.632: INFO/dalvikvm(725): at android.webkit.WebViewCore.nativeTouchUp(Native Method) 12-20 19:29:34.642: INFO/dalvikvm(725): at android.webkit.WebViewCore.access$3300(WebViewCore.java:53) 12-20 19:29:34.652: INFO/dalvikvm(725): at android.webkit.WebViewCore$EventHub$1.handleMessage(WebViewCore.java:1158) 12-20 19:29:34.652: INFO/dalvikvm(725): at android.os.Handler.dispatchMessage(Handler.java:99) 12-20 19:29:34.652: INFO/dalvikvm(725): at android.os.Looper.loop(Looper.java:123) 12-20 19:29:34.652: INFO/dalvikvm(725): at android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:629) 12-20 19:29:34.662: INFO/dalvikvm(725): at java.lang.Thread.run(Thread.java:1019) 12-20 19:29:34.672: ERROR/dalvikvm(725): VM aborting
另外一个方法就是利用addr2line工具,并结合下面这段LOG中给出的堆栈信息找到具体出问题的方法。具体过程参考这篇文章 http://blog./space.php?uid=20564848&do=blog&id=94732
12-20 19:29:34.852: INFO/DEBUG(30): Build fingerprint: 'generic/sdk/generic:2.3/GRH55/79397:eng/test-keys' 12-20 19:29:34.862: INFO/DEBUG(30): pid: 725, tid: 734 >>> XXXXXXXX <<< 12-20 19:29:34.862: INFO/DEBUG(30): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadd00d 12-20 19:29:34.872: INFO/DEBUG(30): r0 fffffebc r1 deadd00d r2 00000026 r3 00000000 12-20 19:29:34.872: INFO/DEBUG(30): r4 81da45c8 r5 4074f6e0 r6 81d8592c r7 0026d2b8 12-20 19:29:34.872: INFO/DEBUG(30): r8 44174b54 r9 43d72e4c 10 43d72e34 fp 41edd82c 12-20 19:29:34.891: INFO/DEBUG(30): ip 81da4728 sp 44174348 lr afd19375 pc 81d45a02 cpsr 20000030 12-20 19:29:35.912: INFO/DEBUG(30): #00 pc 00045a02 /system/lib/libdvm.so 12-20 19:29:35.912: INFO/DEBUG(30): #01 pc 000376fc /system/lib/libdvm.so 12-20 19:29:35.912: INFO/DEBUG(30): #02 pc 000399c4 /system/lib/libdvm.so 12-20 19:29:35.922: INFO/DEBUG(30): #03 pc 0003a4a0 /system/lib/libdvm.so 12-20 19:29:35.932: INFO/DEBUG(30): #04 pc 0032b6d6 /system/lib/libwebcore.so 12-20 19:29:35.952: INFO/DEBUG(30): #05 pc 002a4da4 /system/lib/libwebcore.so 12-20 19:29:35.952: INFO/DEBUG(30): #06 pc 001a6136 /system/lib/libwebcore.so 12-20 19:29:35.952: INFO/DEBUG(30): #07 pc 002a5870 /system/lib/libwebcore.so 12-20 19:29:35.962: INFO/DEBUG(30): #08 pc 00359e36 /system/lib/libwebcore.so 12-20 19:29:35.972: INFO/DEBUG(30): #09 pc 0035d18e /system/lib/libwebcore.so 12-20 19:29:35.972: INFO/DEBUG(30): #10 pc 0036b078 /system/lib/libwebcore.so 12-20 19:29:35.982: INFO/DEBUG(30): #11 pc 003627ac /system/lib/libwebcore.so 12-20 19:29:35.982: INFO/DEBUG(30): #12 pc 0029fb24 /system/lib/libwebcore.so 12-20 19:29:36.002: INFO/DEBUG(30): #13 pc 0023367e /system/lib/libwebcore.so 12-20 19:29:36.002: INFO/DEBUG(30): #14 pc 00239c0c /system/lib/libwebcore.so 12-20 19:29:36.011: INFO/DEBUG(30): #15 pc 00237a28 /system/lib/libwebcore.so 12-20 19:29:36.011: INFO/DEBUG(30): #16 pc 00237b32 /system/lib/libwebcore.so 12-20 19:29:36.022: INFO/DEBUG(30): #17 pc 0023adba /system/lib/libwebcore.so 12-20 19:29:36.022: INFO/DEBUG(30): #18 pc 0023af4e /system/lib/libwebcore.so 12-20 19:29:36.042: INFO/DEBUG(30): #19 pc 000f80c0 /system/lib/libwebcore.so 12-20 19:29:36.042: INFO/DEBUG(30): #20 pc 000f8c66 /system/lib/libwebcore.so 12-20 19:29:36.052: INFO/DEBUG(30): #21 pc 001b81fa /system/lib/libwebcore.so 12-20 19:29:36.062: INFO/DEBUG(30): #22 pc 001b82f2 /system/lib/libwebcore.so 12-20 19:29:36.062: INFO/DEBUG(30): #23 pc 001b8318 /system/lib/libwebcore.so 12-20 19:29:36.072: INFO/DEBUG(30): #24 pc 00017d34 /system/lib/libdvm.so
下面开始分析这个问题 先把这个地址(http://code.google.com/p/android/issues/detail?id=12987)中,楼主的例子下载下来,安装在机器上运行。发现问题出在WebView.addJavascriptInterface方法中。只要使用Java扩展JS的API,并在脚本中调用到这些API就会出现VM崩溃。 用上面提到的方法进行跟踪,发现问题出现在 /external/webkit/WebCore/bridge/jni/jsc/JavaClassJSC.cpp中的这一句上: if (jarray fields = (jarray)(callJNIMethod<jobject>(aClass, "getFields", "()[Ljava/lang/reflect/Field;"))){ int numFields = env->GetArrayLength(fields); ... } callJNIMethod<jobject>方法内部出现了错误,返回的是一个jstring,在这里把它当jarray使用了。在调用env->GetArrayLength(fields)时,VM会使用/dalvik/vm/CheckJni.c中的checkArray方法对参数进行合法检验,一旦发现参数不是数组,就会调用abortMaybe()关闭VM。
现在问题到了(jarray)(callJNIMethod<jobject>(aClass, "getFields", "()[Ljava/lang/reflect/Field;"))为什么会返回一个字符串上了。 我在测试用的APK中使用System.out.println(t)对注册扩展API时使用的Test对象进行打印,然后把callJNIMethod<jobject>返回的字符串也进行打印,发现两者相同。也就是说,无论给callJNIMethod<jobject>传入什么参数,返回结果都是序列化后的Test对象。 经过跟踪,发现callJNIMethod最终会调用/dalvik/vm/interp/Stack.c中的方法dvmCallMethodV,我在dvmCallMethodV中打印了一下method->name,发现每次callJNIMethod调用的都是toString方法,这就能解释为什么callJNIMethod返回的字符串是序列化后的Test对象的现象了。 看来,是callJNIMethod方法把繁琐的JNI调用封装在一起之后出现的问题。于是我自己写了一个方法来替换callJNIMethod<jobject>: jobject getReturnObject(JNIEnv* env, jobject anInstance, const char* name, const char* signature) { jclass testClass = env->GetObjectClass(anInstance); if (!testClass) { LOGW("error 1"); return NULL; } jmethodID methodID = env->GetMethodID(testClass, name, signature); if (!methodID) { LOGW("error 2"); return NULL; } jobject result = env->CallObjectMethod(anInstance, methodID); if (!result) { LOGW("error 3"); return NULL; } return result; } 把使用callJNIMethod<jobject>的几个地方都用getReturnObject方法进行替换,问题解决。
参考文章 在Android源码的JavaScriptCore引擎中添加LOG http://blog.csdn.net/a345017062/archive/2011/05/04/6394897.aspx android或linux调试addr2line工具锁定命令的使用 http://blog./space.php?uid=20564848&do=blog&id=94732 |
|