Adnroid2.3版本模拟器在使用javascript与webkit互动时候报错为bug

 

 

最近在做android 的webkit与javascript的测试,发现一个严重的问题,在javascript调用android中的java方法时候,在2.3模拟器下回直接导致vm终止,错误代码如下,但是在2.2下面正常,过后尝试在4.0下的结果,此问题困扰了我2天了,找的好辛苦,特共享出来,以免走弯路:

05-01 00:18:07.523: W/dalvikvm(392): JNI WARNING: jarray 0x40543ad0 points to non-array object (Ljava/lang/String;)
05-01 00:18:07.534: I/dalvikvm(392): "WebViewCoreThread" prio=5 tid=9 NATIVE
05-01 00:18:07.534: I/dalvikvm(392):   | group="main" sCount=0 dsCount=0 obj=0x4051e820 self=0x2a5568
05-01 00:18:07.534: I/dalvikvm(392):   | sysTid=400 nice=0 sched=0/0 cgrp=default handle=2774688
05-01 00:18:07.534: I/dalvikvm(392):   | schedstat=( 1153298463 1944733293 111 )
05-01 00:18:07.553: I/dalvikvm(392):   at android.webkit.LoadListener.nativeFinished(Native Method)
05-01 00:18:07.553: I/dalvikvm(392):   at android.webkit.LoadListener.nativeFinished(Native Method)
05-01 00:18:07.563: I/dalvikvm(392):   at android.webkit.LoadListener.tearDown(LoadListener.java:1200)
05-01 00:18:07.563: I/dalvikvm(392):   at android.webkit.LoadListener.handleEndData(LoadListener.java:721)
05-01 00:18:07.563: I/dalvikvm(392):   at android.webkit.LoadListener.handleMessage(LoadListener.java:219)
05-01 00:18:07.573: I/dalvikvm(392):   at android.os.Handler.dispatchMessage(Handler.java:99)
05-01 00:18:07.573: I/dalvikvm(392):   at android.os.Looper.loop(Looper.java:123)
05-01 00:18:07.573: I/dalvikvm(392):   at android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:629)
05-01 00:18:07.573: I/dalvikvm(392):   at java.lang.Thread.run(Thread.java:1019)
05-01 00:18:07.573: E/dalvikvm(392): VM aborting

 

google对于此问题的回复:

The javascript to java bridge on 2.3 Gingerbread is causing crashes.  This is 100% reproducible using the WebViewDemo application from here: http://code.google.com/p/apps-for-android/source/browse/#svn/trunk/Samples/WebViewDemo.
Note: The project file for that app is a little messed up, however, if you recreate the project, keeping the code the same, you can reproduce the error.  The sample is old, but the code should still run as none of these interfaces have been deprecated.

It is also easily reproducible by creating a simple application that creates a webview, enables javascript, adds a JS interface, then loads a script into the webview. The code for this even simpler app is attached as well as WebViewTest and a secondary Test class as the "bridge".

The demos work as expected when using 2.2

This is a serious issue as it will cause crashes for any app using the webview to do any serious work.  Thanks in advance for taking a look at this.

Attached is the output from logcat as well as the output from adb bugreport.  

 

网上有个牛人对此问题的解决:

下面开始分析这个问题

先把这个地址(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方法进行替换,问题解决。

 

对于牛人的解决方案没有尝试过

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值