1e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch/* 2e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * Copyright (C) 2012 The Android Open Source Project 3e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * 4e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * Licensed under the Apache License, Version 2.0 (the "License"); 5e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * you may not use this file except in compliance with the License. 6e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * You may obtain a copy of the License at 7e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * 8e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * http://www.apache.org/licenses/LICENSE-2.0 9e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * 10e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * Unless required by applicable law or agreed to in writing, software 11e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * distributed under the License is distributed on an "AS IS" BASIS, 12e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * See the License for the specific language governing permissions and 14e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch * limitations under the License. 15e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch */ 16e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 17e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdochpackage android.webkit; 18e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 19dfceaf2cdbc9355b10fd9c17777808fb65e61851Michael Kolbimport android.app.Activity; 20e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdochimport android.app.AlertDialog; 21e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdochimport android.content.Context; 22e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdochimport android.content.DialogInterface; 23e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdochimport android.os.Handler; 24e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdochimport android.os.Looper; 25e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdochimport android.os.Message; 26e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdochimport android.os.Process; 27e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdochimport android.webkit.WebViewCore.EventHub; 28e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 2974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdochimport java.util.HashSet; 3074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdochimport java.util.Iterator; 3174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdochimport java.util.Set; 3274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch 33e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch// A Runnable that will monitor if the WebCore thread is still 34e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch// processing messages by pinging it every so often. It is safe 35e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch// to call the public methods of this class from any thread. 36e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdochclass WebCoreThreadWatchdog implements Runnable { 37e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 38e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // A message with this id is sent by the WebCore thread to notify the 39e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // Watchdog that the WebCore thread is still processing messages 40e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // (i.e. everything is OK). 41e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private static final int IS_ALIVE = 100; 42e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 43e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // This message is placed in the Watchdog's queue and removed when we 44e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // receive an IS_ALIVE. If it is ever processed, we consider the 45e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // WebCore thread unresponsive. 46e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private static final int TIMED_OUT = 101; 47e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 48e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // Wait 10s after hearing back from the WebCore thread before checking it's still alive. 49e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private static final int HEARTBEAT_PERIOD = 10 * 1000; 50e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 51e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // If there's no callback from the WebCore thread for 30s, prompt the user the page has 52e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // become unresponsive. 53e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private static final int TIMEOUT_PERIOD = 30 * 1000; 54e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 55e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // After the first timeout, use a shorter period before re-prompting the user. 56e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private static final int SUBSEQUENT_TIMEOUT_PERIOD = 15 * 1000; 57e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 58e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private Handler mWebCoreThreadHandler; 59e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private Handler mHandler; 60e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private boolean mPaused; 61e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 6274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch private Set<WebViewClassic> mWebViews; 6374d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch 64e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private static WebCoreThreadWatchdog sInstance; 65e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 6674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch public synchronized static WebCoreThreadWatchdog start(Handler webCoreThreadHandler) { 67e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch if (sInstance == null) { 6874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch sInstance = new WebCoreThreadWatchdog(webCoreThreadHandler); 69e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch new Thread(sInstance, "WebCoreThreadWatchdog").start(); 70e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 71e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch return sInstance; 72e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 73e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 7474d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch public synchronized static void registerWebView(WebViewClassic w) { 75e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch if (sInstance != null) { 7674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch sInstance.addWebView(w); 7774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 7874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 7974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch 8074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch public synchronized static void unregisterWebView(WebViewClassic w) { 8174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch if (sInstance != null) { 8274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch sInstance.removeWebView(w); 83e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 84e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 85e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 86e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch public synchronized static void pause() { 87e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch if (sInstance != null) { 88e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch sInstance.pauseWatchdog(); 89e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 90e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 91e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 92e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch public synchronized static void resume() { 93e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch if (sInstance != null) { 94e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch sInstance.resumeWatchdog(); 95e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 96e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 97e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 9874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch private void addWebView(WebViewClassic w) { 9974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch if (mWebViews == null) { 10074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch mWebViews = new HashSet<WebViewClassic>(); 10174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 10274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch mWebViews.add(w); 103e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 104e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 10574d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch private void removeWebView(WebViewClassic w) { 10674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch mWebViews.remove(w); 10774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 10874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch 10974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch private WebCoreThreadWatchdog(Handler webCoreThreadHandler) { 110e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mWebCoreThreadHandler = webCoreThreadHandler; 111e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 112e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 113e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private void pauseWatchdog() { 114e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mPaused = true; 115e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 116e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch if (mHandler == null) { 117e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch return; 118e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 119e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 120e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mHandler.removeMessages(TIMED_OUT); 121e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mHandler.removeMessages(IS_ALIVE); 122e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mWebCoreThreadHandler.removeMessages(EventHub.HEARTBEAT); 123e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 124e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 125e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch private void resumeWatchdog() { 126e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch if (!mPaused) { 127e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // Do nothing if we get a call to resume without being paused. 128e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // This can happen during the initialisation of the WebView. 129e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch return; 130e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 131e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 132e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mPaused = false; 133e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 134e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch if (mHandler == null) { 135e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch return; 136e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 137e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 138e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mWebCoreThreadHandler.obtainMessage(EventHub.HEARTBEAT, 139e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mHandler.obtainMessage(IS_ALIVE)).sendToTarget(); 140e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mHandler.sendMessageDelayed(mHandler.obtainMessage(TIMED_OUT), TIMEOUT_PERIOD); 141e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 142e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 143b5622b60085086b753ae3ab64168099d0c1471bfBen Murdoch private void createHandler() { 144e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch synchronized (WebCoreThreadWatchdog.class) { 145e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mHandler = new Handler() { 146e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch @Override 147e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch public void handleMessage(Message msg) { 148e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch switch (msg.what) { 149e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch case IS_ALIVE: 150e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch synchronized(WebCoreThreadWatchdog.class) { 151e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch if (mPaused) { 152e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch return; 153e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 154e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 155e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // The WebCore thread still seems alive. Reset the countdown timer. 156e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch removeMessages(TIMED_OUT); 157e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch sendMessageDelayed(obtainMessage(TIMED_OUT), TIMEOUT_PERIOD); 158e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mWebCoreThreadHandler.sendMessageDelayed( 159e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mWebCoreThreadHandler.obtainMessage(EventHub.HEARTBEAT, 160e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mHandler.obtainMessage(IS_ALIVE)), 161e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch HEARTBEAT_PERIOD); 162e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 163e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch break; 164e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 165e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch case TIMED_OUT: 16674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch boolean postedDialog = false; 16774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch synchronized (WebCoreThreadWatchdog.class) { 16874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch Iterator<WebViewClassic> it = mWebViews.iterator(); 16974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // Check each WebView we are aware of and find one that is capable of 17074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // showing the user a prompt dialog. 17174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch while (it.hasNext()) { 17274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch WebView activeView = it.next().getWebView(); 17374d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch 17474d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch if (activeView.getWindowToken() != null && 17574d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch activeView.getViewRootImpl() != null) { 17674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch postedDialog = activeView.post(new PageNotRespondingRunnable( 17774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch activeView.getContext(), this)); 17874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch 17974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch if (postedDialog) { 18074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // We placed the message into the UI thread for an attached 18174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // WebView so we've made our best attempt to display the 18274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // "page not responding" dialog to the user. Although the 18374d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // message is in the queue, there is no guarantee when/if 18474d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // the runnable will execute. In the case that the runnable 18574d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // never executes, the user will need to terminate the 18674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // process manually. 18774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch break; 188e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 18974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 19074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 19174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch 19274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch if (!postedDialog) { 19374d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // There's no active webview we can use to show the dialog, so 19474d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // wait again. If we never get a usable view, the user will 19574d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // never get the chance to terminate the process, and will 19674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // need to do it manually. 19774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch sendMessageDelayed(obtainMessage(TIMED_OUT), 19874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch SUBSEQUENT_TIMEOUT_PERIOD); 19974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 20074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 201e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch break; 202e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 203e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 204e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch }; 205e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 206e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 207e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 208e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch @Override 209e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch public void run() { 210e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch Looper.prepare(); 211e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 212b5622b60085086b753ae3ab64168099d0c1471bfBen Murdoch createHandler(); 213e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 214e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // Send the initial control to WebViewCore and start the timeout timer as long as we aren't 215e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch // paused. 216e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch synchronized (WebCoreThreadWatchdog.class) { 217e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch if (!mPaused) { 218e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mWebCoreThreadHandler.obtainMessage(EventHub.HEARTBEAT, 219e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mHandler.obtainMessage(IS_ALIVE)).sendToTarget(); 220e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch mHandler.sendMessageDelayed(mHandler.obtainMessage(TIMED_OUT), TIMEOUT_PERIOD); 221e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 222e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 223e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch 224e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch Looper.loop(); 225e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch } 22674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch 22774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch private class PageNotRespondingRunnable implements Runnable { 22874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch Context mContext; 22974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch private Handler mWatchdogHandler; 23074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch 23174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch public PageNotRespondingRunnable(Context context, Handler watchdogHandler) { 23274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch mContext = context; 23374d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch mWatchdogHandler = watchdogHandler; 23474d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 23574d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch 23674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch @Override 23774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch public void run() { 23874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // This must run on the UI thread as it is displaying an AlertDialog. 23974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch assert Looper.getMainLooper().getThread() == Thread.currentThread(); 24074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch new AlertDialog.Builder(mContext) 24174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch .setMessage(com.android.internal.R.string.webpage_unresponsive) 24274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch .setPositiveButton(com.android.internal.R.string.force_close, 24374d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch new DialogInterface.OnClickListener() { 24474d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch @Override 24574d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch public void onClick(DialogInterface dialog, int which) { 24674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // User chose to force close. 24774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch Process.killProcess(Process.myPid()); 24874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 24974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch }) 25074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch .setNegativeButton(com.android.internal.R.string.wait, 25174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch new DialogInterface.OnClickListener() { 25274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch @Override 25374d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch public void onClick(DialogInterface dialog, int which) { 25474d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // The user chose to wait. The last HEARTBEAT message 25574d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // will still be in the WebCore thread's queue, so all 25674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // we need to do is post another TIMED_OUT so that the 25774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // user will get prompted again if the WebCore thread 25874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch // doesn't sort itself out. 25974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch mWatchdogHandler.sendMessageDelayed( 26074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch mWatchdogHandler.obtainMessage(TIMED_OUT), 26174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch SUBSEQUENT_TIMEOUT_PERIOD); 26274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 26374d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch }) 26474d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch .setOnCancelListener( 26574d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch new DialogInterface.OnCancelListener() { 26674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch @Override 26774d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch public void onCancel(DialogInterface dialog) { 26874d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch mWatchdogHandler.sendMessageDelayed( 26974d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch mWatchdogHandler.obtainMessage(TIMED_OUT), 27074d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch SUBSEQUENT_TIMEOUT_PERIOD); 27174d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 27274d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch }) 27374d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch .setIcon(android.R.drawable.ic_dialog_alert) 27474d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch .show(); 27574d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 27674d37b965345cfe9c4ac65271cc2658dcc1f5350Ben Murdoch } 277e2e20835835c1ef214e72d9874671aba212e0a94Ben Murdoch} 278