私のアプリからこの例外が原因で発生した多数のクラッシュ ログを取得します (これは 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 クラスには 4 つのメンバーがあります。
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
IMessenger mMessenger;
mQueue は mLooper.mQueue として設定され、mCallback は sWebCoreHandler で 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() を呼び出すことができます。
注:簡単なテストを行ったところですが、元の例外を確実に再現できないため、この問題が解決されたかどうかはわかりません。
このアプローチを試す場合は、十分なテストを行ってください。