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