我从我的应用程序(严重依赖于 webview)中得到了几十个由这个异常引起的崩溃日志,涉及的 ROM 版本是 4.0.4 和 4.0.3。
似乎没有正常的方法来修复它,所以我尝试了以下黑客方法。
4.0.4 上的代码片段:
private static Handler sWebCoreHandler;
// Class for providing Handler creation inside the WebCore thread.
private static class WebCoreThread implements Runnable {
// Message id for initializing a new WebViewCore.
private static final int INITIALIZE = 0;
private static final int REDUCE_PRIORITY = 1;
private static final int RESUME_PRIORITY = 2;
public void run() {
Looper.prepare();
Assert.assertNull(sWebCoreHandler);
synchronized (WebViewCore.class) {
sWebCoreHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
// Process.setPriority(...)
}
};
// ...
}
// ...
}
}
我认为这个异常是从 sWebCoreHandler.handleMessage() 抛出的,如果我们可以在 handleMessage() 上包装 try/catch,问题就可以解决。
Handler 类有四个成员:
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
IMessenger mMessenger;
mQueue 设置为 mLooper.mQueue,sWebCoreHandler 中的 mCallback 为 null,所以我们只需在 sWebCoreHandler 中设置 mLooper 和 mMessenger 的值。
static Handler sProxyHandler = null;
static void tryTweakWebCoreHandler() {
// 4.0.3/4.0.4 rom
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
tweakWebCoreHandle();
}
}
static private void tweakWebCoreHandle() {
if (sProxyHandler != null)
return;
try {
Field f = Class.forName("android.webkit.WebViewCore").getDeclaredField("sWebCoreHandler");
f.setAccessible(true);
Object h = f.get(null);
Object mMessenger = null;
Method m = Handler.class.getDeclaredMethod("getIMessenger", (Class<?>[])null);
m.setAccessible(true);
mMessenger = m.invoke(h, (Object[])null);
sProxyHandler = new WebCoreProxyHandler((Handler)h);
if (mMessenger != null) {
Field f1 = Handler.class.getDeclaredField("mMessenger");
f1.setAccessible(true);
f1.set(sProxyHandler, mMessenger);
}
f.set(null, sProxyHandler);
// Log.w(TAG, "sWebCoreHandler: " + h);
} catch (Throwable e) {
Log.w(TAG, "exception: " + e);
}
if (sProxyHandler == null)
sProxyHandler = new Handler();
}
static class WebCoreProxyHandler extends Handler {
final Handler handler;
public WebCoreProxyHandler(Handler handler) {
super(handler.getLooper());
this.handler = handler;
}
public void handleMessage(Message msg) {
// Log.w("WebCoreProxyHandler", "handle msg: " + msg.what);
try {
handler.handleMessage(msg);
} catch (Throwable tr) {
Log.w("WebCoreProxyHandler", "exception: " + tr);
}
}
}
剩下的问题是何时调用 tryTweakWebCoreHandler()。我尝试在某些设备上创建并测试 WebView 实例后调用它,可以调用 WebCoreProxyHandler.handleMessage()。
注意:我只是做了一些简单的测试,我不确定这个问题是否得到解决,因为原始异常无法可靠地重现。
如果您决定尝试这种方法,请进行足够的测试。