thread_watcher.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/metrics/thread_watcher.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <math.h>  // ceil
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/alias.h"
126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/debug/debugger.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/debug/dump_without_crashing.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/metrics/field_trial.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_tokenizer.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_version_info.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/logging_chrome.h"
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/notification_service.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The following are unique function names for forcing the crash when a thread
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is unresponsive. This makes it possible to tell from the callstack alone what
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread was unresponsive.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We disable optimizations for this block of functions so the compiler doesn't
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// merge them all together.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MSVC_DISABLE_OPTIMIZE()
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MSVC_PUSH_DISABLE_WARNING(4748)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void ReportThreadHang() {
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#if defined(NDEBUG)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::debug::DumpWithoutCrashing();
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#else
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  base::debug::BreakDebugger();
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if !defined(OS_ANDROID) || !defined(NDEBUG)
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// TODO(rtenneti): Enabled crashing, after getting data.
556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)NOINLINE void StartupHang() {
566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ReportThreadHang();
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif  // OS_ANDROID
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)NOINLINE void ShutdownHang() {
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ReportThreadHang();
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NOINLINE void ThreadUnresponsive_UI() {
656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ReportThreadHang();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NOINLINE void ThreadUnresponsive_DB() {
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ReportThreadHang();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NOINLINE void ThreadUnresponsive_FILE() {
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ReportThreadHang();
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NOINLINE void ThreadUnresponsive_FILE_USER_BLOCKING() {
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ReportThreadHang();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NOINLINE void ThreadUnresponsive_PROCESS_LAUNCHER() {
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ReportThreadHang();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NOINLINE void ThreadUnresponsive_CACHE() {
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ReportThreadHang();
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NOINLINE void ThreadUnresponsive_IO() {
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ReportThreadHang();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MSVC_POP_WARNING()
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MSVC_ENABLE_OPTIMIZE();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CrashBecauseThreadWasUnresponsive(BrowserThread::ID thread_id) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::debug::Alias(&thread_id);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (thread_id) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BrowserThread::UI:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadUnresponsive_UI();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BrowserThread::DB:
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadUnresponsive_DB();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BrowserThread::FILE:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadUnresponsive_FILE();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BrowserThread::FILE_USER_BLOCKING:
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadUnresponsive_FILE_USER_BLOCKING();
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BrowserThread::PROCESS_LAUNCHER:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadUnresponsive_PROCESS_LAUNCHER();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BrowserThread::CACHE:
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadUnresponsive_CACHE();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BrowserThread::IO:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadUnresponsive_IO();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BrowserThread::ID_COUNT:
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CHECK(false);  // This shouldn't actually be reached!
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Omission of the default hander is intentional -- that way the compiler
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // should warn if our switch becomes outdated.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(false) << "Unknown thread was unresponsive.";  // Shouldn't be reached.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ThreadWatcher methods and members.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThreadWatcher::ThreadWatcher(const WatchingParams& params)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : thread_id_(params.thread_id),
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thread_name_(params.thread_name),
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      watched_loop_(
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BrowserThread::GetMessageLoopProxyForThread(params.thread_id)),
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sleep_time_(params.sleep_time),
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unresponsive_time_(params.unresponsive_time),
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ping_time_(base::TimeTicks::Now()),
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pong_time_(ping_time_),
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ping_sequence_number_(0),
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      active_(false),
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ping_count_(params.unresponsive_threshold),
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_time_histogram_(NULL),
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unresponsive_time_histogram_(NULL),
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unresponsive_count_(0),
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hung_processing_complete_(false),
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unresponsive_threshold_(params.unresponsive_threshold),
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crash_on_hang_(params.crash_on_hang),
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      live_threads_threshold_(params.live_threads_threshold),
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Initialize();
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThreadWatcher::~ThreadWatcher() {}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::StartWatching(const WatchingParams& params) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(params.sleep_time.InMilliseconds(), 0);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(params.unresponsive_time.InMilliseconds(),
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            params.sleep_time.InMilliseconds());
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we are not on WatchDogThread, then post a task to call StartWatching on
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WatchDogThread.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!WatchDogThread::CurrentlyOnWatchDogThread()) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WatchDogThread::PostTask(
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&ThreadWatcher::StartWatching, params));
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a new thread watcher object for the given thread and activate it.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadWatcher* watcher = new ThreadWatcher(params);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(watcher);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we couldn't register the thread watcher object, we are shutting down,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // then don't activate thread watching.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ThreadWatcherList::IsRegistered(params.thread_id))
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  watcher->ActivateThreadWatching();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::ActivateThreadWatching() {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (active_) return;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  active_ = true;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ping_count_ = unresponsive_threshold_;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResetHangCounters();
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ThreadWatcher::PostPingMessage,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()));
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::DeActivateThreadWatching() {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  active_ = false;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ping_count_ = 0;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::WakeUp() {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There is some user activity, PostPingMessage task of thread watcher if
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // needed.
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!active_) return;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Throw away the previous |unresponsive_count_| and start over again. Just
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // before going to sleep, |unresponsive_count_| could be very close to
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |unresponsive_threshold_| and when user becomes active,
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |unresponsive_count_| can go over |unresponsive_threshold_| if there was no
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // response for ping messages. Reset |unresponsive_count_| to start measuring
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the unresponsiveness of the threads when system becomes active.
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unresponsive_count_ = 0;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ping_count_ <= 0) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ping_count_ = unresponsive_threshold_;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResetHangCounters();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PostPingMessage();
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ping_count_ = unresponsive_threshold_;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::PostPingMessage() {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we have stopped watching or if the user is idle, then stop sending
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ping messages.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!active_ || ping_count_ <= 0)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save the current time when we have sent ping message.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ping_time_ = base::TimeTicks::Now();
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send a ping message to the watched thread. Callback will be called on
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the WatchDogThread.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Closure callback(
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ThreadWatcher::OnPongMessage, weak_ptr_factory_.GetWeakPtr(),
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 ping_sequence_number_));
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (watched_loop_->PostTask(
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&ThreadWatcher::OnPingMessage, thread_id_,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     callback))) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Post a task to check the responsiveness of watched thread.
24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::MessageLoop::current()->PostDelayedTask(
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&ThreadWatcher::OnCheckResponsiveness,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(), ping_sequence_number_),
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          unresponsive_time_);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Watched thread might have gone away, stop watching it.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeActivateThreadWatching();
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::OnPongMessage(uint64 ping_sequence_number) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record watched thread's response time.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks now = base::TimeTicks::Now();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta response_time = now - ping_time_;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response_time_histogram_->AddTime(response_time);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save the current time when we have got pong message.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pong_time_ = now;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if there are any extra pings in flight.
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(ping_sequence_number_, ping_sequence_number);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ping_sequence_number_ != ping_sequence_number)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Increment sequence number for the next ping message to indicate watched
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread is responsive.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++ping_sequence_number_;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we have stopped watching or if the user is idle, then stop sending
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ping messages.
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!active_ || --ping_count_ <= 0)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ThreadWatcher::PostPingMessage,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()),
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sleep_time_);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::OnCheckResponsiveness(uint64 ping_sequence_number) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we have stopped watching then consider thread as responding.
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!active_) {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    responsive_ = true;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the latest ping_sequence_number_ is not same as the ping_sequence_number
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that is passed in, then we can assume OnPongMessage was called.
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // OnPongMessage increments ping_sequence_number_.
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ping_sequence_number_ != ping_sequence_number) {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Reset unresponsive_count_ to zero because we got a response from the
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // watched thread.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResetHangCounters();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    responsive_ = true;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record that we got no response from watched thread.
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GotNoResponse();
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Post a task to check the responsiveness of watched thread.
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ThreadWatcher::OnCheckResponsiveness,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr(), ping_sequence_number_),
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unresponsive_time_);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  responsive_ = false;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::Initialize() {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadWatcherList::Register(this);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string response_time_histogram_name =
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ThreadWatcher.ResponseTime." + thread_name_;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response_time_histogram_ = base::Histogram::FactoryTimeGet(
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_time_histogram_name,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(1),
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(100), 50,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Histogram::kUmaTargetedHistogramFlag);
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string unresponsive_time_histogram_name =
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ThreadWatcher.Unresponsive." + thread_name_;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unresponsive_time_histogram_ = base::Histogram::FactoryTimeGet(
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unresponsive_time_histogram_name,
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(1),
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(100), 50,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Histogram::kUmaTargetedHistogramFlag);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string responsive_count_histogram_name =
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ThreadWatcher.ResponsiveThreads." + thread_name_;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  responsive_count_histogram_ = base::LinearHistogram::FactoryGet(
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      responsive_count_histogram_name, 1, 10, 11,
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Histogram::kUmaTargetedHistogramFlag);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string unresponsive_count_histogram_name =
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ThreadWatcher.UnresponsiveThreads." + thread_name_;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unresponsive_count_histogram_ = base::LinearHistogram::FactoryGet(
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unresponsive_count_histogram_name, 1, 10, 11,
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Histogram::kUmaTargetedHistogramFlag);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::OnPingMessage(const BrowserThread::ID& thread_id,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const base::Closure& callback_task) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method is called on watched thread.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(thread_id));
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WatchDogThread::PostTask(FROM_HERE, callback_task);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::ResetHangCounters() {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unresponsive_count_ = 0;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hung_processing_complete_ = false;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcher::GotNoResponse() {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++unresponsive_count_;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsVeryUnresponsive())
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record total unresponsive_time since last pong message.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta unresponse_time = base::TimeTicks::Now() - pong_time_;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unresponsive_time_histogram_->AddTime(unresponse_time);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We have already collected stats for the non-responding watched thread.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hung_processing_complete_)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record how other threads are responding.
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 responding_thread_count = 0;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 unresponding_thread_count = 0;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadWatcherList::GetStatusOfThreads(&responding_thread_count,
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        &unresponding_thread_count);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record how many watched threads are responding.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  responsive_count_histogram_->Add(responding_thread_count);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record how many watched threads are not responding.
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unresponsive_count_histogram_->Add(unresponding_thread_count);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Crash the browser if the watched thread is to be crashed on hang and if the
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // number of other threads responding is less than or equal to
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // live_threads_threshold_ and at least one other thread is responding.
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (crash_on_hang_ &&
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      responding_thread_count > 0 &&
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      responding_thread_count <= live_threads_threshold_) {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static bool crashed_once = false;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!crashed_once) {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crashed_once = true;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CrashBecauseThreadWasUnresponsive(thread_id_);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hung_processing_complete_ = true;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThreadWatcher::IsVeryUnresponsive() {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return unresponsive_count_ >= unresponsive_threshold_;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ThreadWatcherList methods and members.
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThreadWatcherList* ThreadWatcherList::g_thread_watcher_list_ = NULL;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
416a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ThreadWatcherList::g_stopped_ = false;
417a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int ThreadWatcherList::kSleepSeconds = 1;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int ThreadWatcherList::kUnresponsiveSeconds = 2;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
42258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochconst int ThreadWatcherList::kUnresponsiveCount = 9;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int ThreadWatcherList::kLiveThreadsThreshold = 2;
425a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static, non-const for tests.
426a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int ThreadWatcherList::g_initialize_delay_seconds = 120;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ThreadWatcherList::CrashDataThresholds::CrashDataThresholds(
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 live_threads_threshold,
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 unresponsive_threshold)
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : live_threads_threshold(live_threads_threshold),
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      unresponsive_threshold(unresponsive_threshold) {
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ThreadWatcherList::CrashDataThresholds::CrashDataThresholds()
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : live_threads_threshold(kLiveThreadsThreshold),
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      unresponsive_threshold(kUnresponsiveCount) {
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherList::StartWatchingAll(const CommandLine& command_line) {
4424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // TODO(rtenneti): Enable ThreadWatcher.
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 unresponsive_threshold;
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CrashOnHangThreadMap crash_on_hang_threads;
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ParseCommandLine(command_line,
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   &unresponsive_threshold,
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   &crash_on_hang_threads);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadWatcherObserver::SetupNotifications(
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kSleepSeconds * unresponsive_threshold));
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
452a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  WatchDogThread::PostTask(
453a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
454a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&ThreadWatcherList::SetStopped, false));
455a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WatchDogThread::PostDelayedTask(
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ThreadWatcherList::InitializeAndStartWatching,
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 unresponsive_threshold,
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 crash_on_hang_threads),
461a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TimeDelta::FromSeconds(g_initialize_delay_seconds));
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherList::StopWatchingAll() {
4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // TODO(rtenneti): Enable ThreadWatcher.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadWatcherObserver::RemoveNotifications();
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteAll();
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherList::Register(ThreadWatcher* watcher) {
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_thread_watcher_list_)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!g_thread_watcher_list_->Find(watcher->thread_id()));
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_thread_watcher_list_->registered_[watcher->thread_id()] = watcher;
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThreadWatcherList::IsRegistered(const BrowserThread::ID thread_id) {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL != ThreadWatcherList::Find(thread_id);
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherList::GetStatusOfThreads(uint32* responding_thread_count,
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           uint32* unresponding_thread_count) {
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *responding_thread_count = 0;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *unresponding_thread_count = 0;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_thread_watcher_list_)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (RegistrationList::iterator it =
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           g_thread_watcher_list_->registered_.begin();
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       g_thread_watcher_list_->registered_.end() != it;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it->second->IsVeryUnresponsive())
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++(*unresponding_thread_count);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++(*responding_thread_count);
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherList::WakeUpAll() {
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_thread_watcher_list_)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (RegistrationList::iterator it =
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           g_thread_watcher_list_->registered_.begin();
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       g_thread_watcher_list_->registered_.end() != it;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    it->second->WakeUp();
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThreadWatcherList::ThreadWatcherList() {
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!g_thread_watcher_list_);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_thread_watcher_list_ = this;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThreadWatcherList::~ThreadWatcherList() {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(this == g_thread_watcher_list_);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_thread_watcher_list_ = NULL;
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherList::ParseCommandLine(
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CommandLine& command_line,
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32* unresponsive_threshold,
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CrashOnHangThreadMap* crash_on_hang_threads) {
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Initialize |unresponsive_threshold| to a default value.
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *unresponsive_threshold = kUnresponsiveCount;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Increase the unresponsive_threshold on the Stable and Beta channels to
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reduce the number of crashes due to ThreadWatcher.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (channel == chrome::VersionInfo::CHANNEL_STABLE) {
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *unresponsive_threshold *= 4;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (channel == chrome::VersionInfo::CHANNEL_BETA) {
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *unresponsive_threshold *= 2;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For Windows XP (old systems), double the unresponsive_threshold to give
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the OS a chance to schedule UI/IO threads a time slice to respond with a
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pong message (to get around limitations with the OS).
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() <= base::win::VERSION_XP)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *unresponsive_threshold *= 2;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint32 crash_seconds = *unresponsive_threshold * kUnresponsiveSeconds;
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string crash_on_hang_thread_names;
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool has_command_line_overwrite = false;
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command_line.HasSwitch(switches::kCrashOnHangThreads)) {
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    crash_on_hang_thread_names =
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        command_line.GetSwitchValueASCII(switches::kCrashOnHangThreads);
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    has_command_line_overwrite = true;
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (channel != chrome::VersionInfo::CHANNEL_STABLE) {
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Default to crashing the browser if UI or IO or FILE threads are not
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // responsive except in stable channel.
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    crash_on_hang_thread_names = base::StringPrintf(
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "UI:%d:%d,IO:%d:%d,FILE:%d:%d",
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        kLiveThreadsThreshold, crash_seconds,
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        kLiveThreadsThreshold, crash_seconds,
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        kLiveThreadsThreshold, crash_seconds * 5);
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ParseCommandLineCrashOnHangThreads(crash_on_hang_thread_names,
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     kLiveThreadsThreshold,
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     crash_seconds,
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     crash_on_hang_threads);
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (channel != chrome::VersionInfo::CHANNEL_CANARY ||
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      has_command_line_overwrite) {
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const char* kFieldTrialName = "ThreadWatcher";
5840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
5850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Nothing else to be done if the trial has already been set (i.e., when
5860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // StartWatchingAll() has been already called once).
5870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (base::FieldTrialList::TrialExists(kFieldTrialName))
5880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
5890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Set up a field trial for 100% of the users to crash if either UI or IO
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // thread is not responsive for 30 seconds (or 15 pings).
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::FieldTrial> field_trial(
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FieldTrialList::FactoryGetFieldTrial(
5940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          kFieldTrialName, 100, "default_hung_threads",
5954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          2014, 10, 30, base::FieldTrial::SESSION_RANDOMIZED, NULL));
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int hung_thread_group = field_trial->AppendGroup("hung_thread", 100);
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (field_trial->group() == hung_thread_group) {
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (CrashOnHangThreadMap::iterator it = crash_on_hang_threads->begin();
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         crash_on_hang_threads->end() != it;
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         ++it) {
6014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (it->first == "FILE")
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      it->second.live_threads_threshold = INT_MAX;
6044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (it->first == "UI") {
6054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // TODO(rtenneti): set unresponsive threshold to 120 seconds to catch
6064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // the worst UI hangs and for fewer crashes due to ThreadWatcher. Reduce
6074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // it to a more reasonable time ala IO thread.
6084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        it->second.unresponsive_threshold = 60;
6094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      } else {
6104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        it->second.unresponsive_threshold = 15;
6114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ThreadWatcherList::ParseCommandLineCrashOnHangThreads(
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& crash_on_hang_thread_names,
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 default_live_threads_threshold,
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 default_crash_seconds,
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CrashOnHangThreadMap* crash_on_hang_threads) {
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::StringTokenizer tokens(crash_on_hang_thread_names, ",");
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::string> values;
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (tokens.GetNext()) {
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& token = tokens.token();
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::SplitString(token, ':', &values);
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string thread_name = values[0];
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 live_threads_threshold = default_live_threads_threshold;
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 crash_seconds = default_crash_seconds;
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (values.size() >= 2 &&
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (!base::StringToUint(values[1], &live_threads_threshold))) {
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (values.size() >= 3 &&
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (!base::StringToUint(values[2], &crash_seconds))) {
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 unresponsive_threshold = static_cast<uint32>(
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ceil(static_cast<float>(crash_seconds) / kUnresponsiveSeconds));
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CrashDataThresholds crash_data(live_threads_threshold,
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   unresponsive_threshold);
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Use the last specifier.
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (*crash_on_hang_threads)[thread_name] = crash_data;
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherList::InitializeAndStartWatching(
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 unresponsive_threshold,
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const CrashOnHangThreadMap& crash_on_hang_threads) {
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Disarm the startup timebomb, even if stop has been called.
656f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  BrowserThread::PostTask(
657f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      BrowserThread::UI,
658f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      FROM_HERE,
659f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      base::Bind(&StartupTimeBomb::DisarmStartupTimeBomb));
660f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
661a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // This method is deferred in relationship to its StopWatchingAll()
662a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // counterpart. If a previous initialization has already happened, or if
663a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // stop has been called, there's nothing left to do here.
664a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (g_thread_watcher_list_ || g_stopped_)
665a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
666a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadWatcherList* thread_watcher_list = new ThreadWatcherList();
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(thread_watcher_list);
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::TimeDelta kSleepTime =
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kSleepSeconds);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::TimeDelta kUnresponsiveTime =
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kUnresponsiveSeconds);
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartWatching(BrowserThread::UI, "UI", kSleepTime, kUnresponsiveTime,
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                unresponsive_threshold, crash_on_hang_threads);
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartWatching(BrowserThread::IO, "IO", kSleepTime, kUnresponsiveTime,
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                unresponsive_threshold, crash_on_hang_threads);
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartWatching(BrowserThread::DB, "DB", kSleepTime, kUnresponsiveTime,
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                unresponsive_threshold, crash_on_hang_threads);
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartWatching(BrowserThread::FILE, "FILE", kSleepTime, kUnresponsiveTime,
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                unresponsive_threshold, crash_on_hang_threads);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartWatching(BrowserThread::CACHE, "CACHE", kSleepTime, kUnresponsiveTime,
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                unresponsive_threshold, crash_on_hang_threads);
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherList::StartWatching(
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BrowserThread::ID& thread_id,
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& thread_name,
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::TimeDelta& sleep_time,
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::TimeDelta& unresponsive_time,
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 unresponsive_threshold,
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const CrashOnHangThreadMap& crash_on_hang_threads) {
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CrashOnHangThreadMap::const_iterator it =
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      crash_on_hang_threads.find(thread_name);
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool crash_on_hang = false;
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint32 live_threads_threshold = 0;
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it != crash_on_hang_threads.end()) {
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    crash_on_hang = true;
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    live_threads_threshold = it->second.live_threads_threshold;
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unresponsive_threshold = it->second.unresponsive_threshold;
7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadWatcher::StartWatching(
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ThreadWatcher::WatchingParams(thread_id,
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    thread_name,
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    sleep_time,
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    unresponsive_time,
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    unresponsive_threshold,
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    crash_on_hang,
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    live_threads_threshold));
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherList::DeleteAll() {
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!WatchDogThread::CurrentlyOnWatchDogThread()) {
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WatchDogThread::PostTask(
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&ThreadWatcherList::DeleteAll));
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
727a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
728a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SetStopped(true);
729a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_thread_watcher_list_)
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete all thread watcher objects.
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!g_thread_watcher_list_->registered_.empty()) {
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegistrationList::iterator it = g_thread_watcher_list_->registered_.begin();
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete it->second;
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_thread_watcher_list_->registered_.erase(it);
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete g_thread_watcher_list_;
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThreadWatcher* ThreadWatcherList::Find(const BrowserThread::ID& thread_id) {
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_thread_watcher_list_)
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegistrationList::iterator it =
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_thread_watcher_list_->registered_.find(thread_id);
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_thread_watcher_list_->registered_.end() == it)
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return it->second;
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static
756a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ThreadWatcherList::SetStopped(bool stopped) {
757a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
758a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  g_stopped_ = stopped;
759a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
760a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ThreadWatcherObserver methods and members.
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThreadWatcherObserver* ThreadWatcherObserver::g_thread_watcher_observer_ = NULL;
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThreadWatcherObserver::ThreadWatcherObserver(
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::TimeDelta& wakeup_interval)
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : last_wakeup_time_(base::TimeTicks::Now()),
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wakeup_interval_(wakeup_interval) {
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!g_thread_watcher_observer_);
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_thread_watcher_observer_ = this;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThreadWatcherObserver::~ThreadWatcherObserver() {
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(this == g_thread_watcher_observer_);
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_thread_watcher_observer_ = NULL;
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherObserver::SetupNotifications(
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::TimeDelta& wakeup_interval) {
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ThreadWatcherObserver* observer = new ThreadWatcherObserver(wakeup_interval);
784cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  observer->registrar_.Add(
785cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      observer,
786cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      chrome::NOTIFICATION_BROWSER_OPENED,
787cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      content::NotificationService::AllBrowserContextsAndSources());
788cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  observer->registrar_.Add(observer,
789cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           chrome::NOTIFICATION_BROWSER_CLOSED,
790cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NotificationService::AllSources());
791cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  observer->registrar_.Add(observer,
792cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           chrome::NOTIFICATION_TAB_PARENTED,
793cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NotificationService::AllSources());
794cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  observer->registrar_.Add(observer,
795cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           chrome::NOTIFICATION_TAB_CLOSING,
796cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NotificationService::AllSources());
797cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  observer->registrar_.Add(observer,
798cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NOTIFICATION_LOAD_START,
799cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NotificationService::AllSources());
800cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  observer->registrar_.Add(observer,
801cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NOTIFICATION_LOAD_STOP,
802cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NotificationService::AllSources());
803cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  observer->registrar_.Add(observer,
804cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
805cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NotificationService::AllSources());
806cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  observer->registrar_.Add(observer,
807cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
808cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NotificationService::AllSources());
809cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  observer->registrar_.Add(observer,
810cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
811cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           content::NotificationService::AllSources());
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherObserver::RemoveNotifications() {
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_thread_watcher_observer_)
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_thread_watcher_observer_->registrar_.RemoveAll();
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete g_thread_watcher_observer_;
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThreadWatcherObserver::Observe(
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationSource& source,
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationDetails& details) {
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There is some user activity, see if thread watchers are to be awakened.
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks now = base::TimeTicks::Now();
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((now - last_wakeup_time_) < wakeup_interval_)
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_wakeup_time_ = now;
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WatchDogThread::PostTask(
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ThreadWatcherList::WakeUpAll));
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WatchDogThread methods and members.
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This lock protects g_watchdog_thread.
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<base::Lock>::Leaky
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_watchdog_lock = LAZY_INSTANCE_INITIALIZER;
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The singleton of this class.
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static WatchDogThread* g_watchdog_thread = NULL;
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WatchDogThread::WatchDogThread() : Thread("BrowserWatchdog") {
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WatchDogThread::~WatchDogThread() {
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Stop();
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WatchDogThread::CurrentlyOnWatchDogThread() {
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock lock(g_watchdog_lock.Get());
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_watchdog_thread &&
85790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      g_watchdog_thread->message_loop() == base::MessageLoop::current();
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WatchDogThread::PostTask(const tracked_objects::Location& from_here,
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const base::Closure& task) {
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PostTaskHelper(from_here, task, base::TimeDelta());
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WatchDogThread::PostDelayedTask(const tracked_objects::Location& from_here,
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const base::Closure& task,
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     base::TimeDelta delay) {
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PostTaskHelper(from_here, task, delay);
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WatchDogThread::PostTaskHelper(
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& from_here,
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Closure& task,
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta delay) {
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(g_watchdog_lock.Get());
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
88190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop* message_loop = g_watchdog_thread ?
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        g_watchdog_thread->message_loop() : NULL;
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (message_loop) {
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message_loop->PostDelayedTask(from_here, task, delay);
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WatchDogThread::Init() {
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This thread shouldn't be allowed to perform any blocking disk I/O.
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::SetIOAllowed(false);
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock lock(g_watchdog_lock.Get());
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!g_watchdog_thread);
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_watchdog_thread = this;
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WatchDogThread::CleanUp() {
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock lock(g_watchdog_lock.Get());
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_watchdog_thread = NULL;
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StartupWatchDogThread methods and members.
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Class for detecting hangs during startup.
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class StartupWatchDogThread : public base::Watchdog {
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Constructor specifies how long the StartupWatchDogThread will wait before
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // alarming.
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit StartupWatchDogThread(const base::TimeDelta& duration)
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : base::Watchdog(duration, "Startup watchdog thread", true) {
917010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if defined(OS_ANDROID)
918010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // TODO(rtenneti): Delete this code, after getting data.
919010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    start_time_clock_= base::Time::Now();
920010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    start_time_monotonic_ = base::TimeTicks::Now();
921010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    start_time_thread_now_ = base::TimeTicks::IsThreadNowSupported()
922010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        ? base::TimeTicks::ThreadNow() : base::TimeTicks::Now();
923010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif  // OS_ANDROID
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Alarm is called if the time expires after an Arm() without someone calling
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disarm(). When Alarm goes off, in release mode we get the crash dump
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // without crashing and in debug mode we break into the debugger.
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void Alarm() OVERRIDE {
930010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if !defined(NDEBUG)
9316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    StartupHang();
932010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
933010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#elif !defined(OS_ANDROID)
9346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    WatchDogThread::PostTask(FROM_HERE, base::Bind(&StartupHang));
935010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
936010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#else  // Android release: gather stats to figure out when to crash.
937010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // TODO(rtenneti): Delete this code, after getting data.
938cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("StartupTimeBomb.Alarm.TimeDuration",
939010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                        base::Time::Now() - start_time_clock_);
940cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("StartupTimeBomb.Alarm.TimeTicksDuration",
941010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                        base::TimeTicks::Now() - start_time_monotonic_);
942010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (base::TimeTicks::IsThreadNowSupported()) {
943010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      UMA_HISTOGRAM_TIMES(
944cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          "StartupTimeBomb.Alarm.ThreadNowDuration",
945010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          base::TimeTicks::ThreadNow() - start_time_thread_now_);
946010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
947010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
948010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif  // OS_ANDROID
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
951010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) private:
952010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if defined(OS_ANDROID)
953010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // TODO(rtenneti): Delete this code, after getting data.
954010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::Time start_time_clock_;
955010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::TimeTicks start_time_monotonic_;
956010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::TimeTicks start_time_thread_now_;
957010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif  // OS_ANDROID
958010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(StartupWatchDogThread);
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ShutdownWatchDogThread methods and members.
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Class for detecting hangs during shutdown.
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ShutdownWatchDogThread : public base::Watchdog {
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Constructor specifies how long the ShutdownWatchDogThread will wait before
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // alarming.
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit ShutdownWatchDogThread(const base::TimeDelta& duration)
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : base::Watchdog(duration, "Shutdown watchdog thread", true) {
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Alarm is called if the time expires after an Arm() without someone calling
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disarm(). We crash the browser if this method is called.
9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void Alarm() OVERRIDE {
9766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ShutdownHang();
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
979010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) private:
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShutdownWatchDogThread);
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StartupTimeBomb methods and members.
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupTimeBomb* StartupTimeBomb::g_startup_timebomb_ = NULL;
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupTimeBomb::StartupTimeBomb()
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : startup_watchdog_(NULL),
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thread_id_(base::PlatformThread::CurrentId()) {
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!g_startup_timebomb_);
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_startup_timebomb_ = this;
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupTimeBomb::~StartupTimeBomb() {
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(this == g_startup_timebomb_);
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (startup_watchdog_)
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Disarm();
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_startup_timebomb_ = NULL;
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StartupTimeBomb::Arm(const base::TimeDelta& duration) {
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!startup_watchdog_);
10073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  startup_watchdog_ = new StartupWatchDogThread(duration);
10083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  startup_watchdog_->Arm();
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return;
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StartupTimeBomb::Disarm() {
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (startup_watchdog_) {
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    startup_watchdog_->Disarm();
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    startup_watchdog_->Cleanup();
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeleteStartupWatchdog();
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StartupTimeBomb::DeleteStartupWatchdog() {
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (startup_watchdog_->IsJoinable()) {
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Allow the watchdog thread to shutdown on UI. Watchdog thread shutdowns
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // very fast.
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ThreadRestrictions::SetIOAllowed(true);
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete startup_watchdog_;
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    startup_watchdog_ = NULL;
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
103190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&StartupTimeBomb::DeleteStartupWatchdog,
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this)),
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(10));
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StartupTimeBomb::DisarmStartupTimeBomb() {
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_startup_timebomb_)
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_startup_timebomb_->Disarm();
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ShutdownWatcherHelper methods and members.
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ShutdownWatcherHelper is a wrapper class for detecting hangs during
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shutdown.
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShutdownWatcherHelper::ShutdownWatcherHelper()
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : shutdown_watchdog_(NULL),
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thread_id_(base::PlatformThread::CurrentId()) {
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShutdownWatcherHelper::~ShutdownWatcherHelper() {
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shutdown_watchdog_) {
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shutdown_watchdog_->Disarm();
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete shutdown_watchdog_;
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shutdown_watchdog_ = NULL;
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ShutdownWatcherHelper::Arm(const base::TimeDelta& duration) {
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!shutdown_watchdog_);
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta actual_duration = duration;
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (channel == chrome::VersionInfo::CHANNEL_STABLE) {
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    actual_duration *= 20;
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (channel == chrome::VersionInfo::CHANNEL_BETA ||
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             channel == chrome::VersionInfo::CHANNEL_DEV) {
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    actual_duration *= 10;
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On Windows XP, give twice the time for shutdown.
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() <= base::win::VERSION_XP)
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    actual_duration *= 2;
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shutdown_watchdog_ = new ShutdownWatchDogThread(actual_duration);
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shutdown_watchdog_->Arm();
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085