browser_shutdown.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_shutdown.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/resource_bundle.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_path.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/histogram.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/process_util.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/thread.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/waitable_event.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chrome_thread.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/first_run.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/jankometer.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/metrics_service.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/plugin_process_host.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/pref_service.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/render_process_host.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/render_view_host.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/render_widget_host.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_plugin_lib.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/predictor_api.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/rlz/rlz.h"
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta;
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_shutdown {
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Whether the browser is trying to quit (e.g., Quit chosen from menu).
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool g_trying_to_quit = false;
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTime shutdown_started_;
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochShutdownType shutdown_type_ = NOT_VALID;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint shutdown_num_processes_;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint shutdown_num_processes_slow_;
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool delete_resources_on_shutdown = true;
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kShutdownMsFile[] = "chrome_shutdown_ms.txt";
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid RegisterPrefs(PrefService* local_state) {
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_state->RegisterIntegerPref(prefs::kShutdownType, NOT_VALID);
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_state->RegisterIntegerPref(prefs::kShutdownNumProcesses, 0);
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_state->RegisterIntegerPref(prefs::kShutdownNumProcessesSlow, 0);
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochShutdownType GetShutdownType() {
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return shutdown_type_;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid OnShutdownStarting(ShutdownType type) {
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (shutdown_type_ != NOT_VALID)
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  shutdown_type_ = type;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For now, we're only counting the number of renderer processes
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // since we can't safely count the number of plugin processes from this
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // thread, and we'd really like to avoid anything which might add further
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // delays to shutdown time.
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  shutdown_started_ = Time::Now();
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Call FastShutdown on all of the RenderProcessHosts.  This will be
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // a no-op in some cases, so we still need to go through the normal
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // shutdown path for the ones that didn't exit here.
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  shutdown_num_processes_ = 0;
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  shutdown_num_processes_slow_ = 0;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       !i.IsAtEnd(); i.Advance()) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ++shutdown_num_processes_;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!i.GetCurrentValue()->FastShutdownIfPossible())
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++shutdown_num_processes_slow_;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath GetShutdownMsPath() {
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath shutdown_ms_file;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PathService::Get(chrome::DIR_USER_DATA, &shutdown_ms_file);
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return shutdown_ms_file.AppendASCII(kShutdownMsFile);
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid Shutdown() {
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Unload plugins. This needs to happen on the IO thread.
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ChromeThread::PostTask(
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ChromeThread::IO, FROM_HERE,
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NewRunnableFunction(&ChromePluginLib::UnloadAllPlugins));
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // WARNING: During logoff/shutdown (WM_ENDSESSION) we may not have enough
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // time to get here. If you have something that *must* happen on end session,
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // consider putting it in BrowserProcessImpl::EndSession.
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(g_browser_process);
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Notifies we are going away.
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_browser_process->shutdown_event()->Signal();
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PrefService* prefs = g_browser_process->local_state();
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  chrome_browser_net::SavePredictorStateForNextStartupAndTrim(prefs);
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MetricsService* metrics = g_browser_process->metrics_service();
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (metrics) {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    metrics->RecordCleanShutdown();
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    metrics->RecordCompletedSessionEnd();
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (shutdown_type_ > NOT_VALID && shutdown_num_processes_ > 0) {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Record the shutdown info so that we can put it into a histogram at next
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // startup.
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prefs->SetInteger(prefs::kShutdownType, shutdown_type_);
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prefs->SetInteger(prefs::kShutdownNumProcesses, shutdown_num_processes_);
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prefs->SetInteger(prefs::kShutdownNumProcessesSlow,
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      shutdown_num_processes_slow_);
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check local state for the restart flag so we can restart the session below.
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool restart_last_session = false;
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (prefs->HasPrefPath(prefs::kRestartLastSessionOnShutdown)) {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    restart_last_session =
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        prefs->GetBoolean(prefs::kRestartLastSessionOnShutdown);
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prefs->ClearPref(prefs::kRestartLastSessionOnShutdown);
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->SavePersistentPrefs();
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Cleanup any statics created by RLZ. Must be done before NotificationService
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is destroyed.
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RLZTracker::CleanupRlz();
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The jank'o'meter requires that the browser process has been destroyed
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // before calling UninstallJankometer().
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete g_browser_process;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_browser_process = NULL;
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Uninstall Jank-O-Meter here after the IO thread is no longer running.
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UninstallJankometer();
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (delete_resources_on_shutdown)
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ResourceBundle::CleanupSharedInstance();
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!Upgrade::IsBrowserAlreadyRunning() &&
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      shutdown_type_ != browser_shutdown::END_SESSION) {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Upgrade::SwapNewChromeExeIfPresent();
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (restart_last_session) {
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if !defined(OS_CHROMEOS)
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Make sure to relaunch the browser with the original command line plus
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the Restore Last Session flag. Note that Chrome can be launched (ie.
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // through ShellExecute on Windows) with a switch argument terminator at
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the end (double dash, as described in b/1366444) plus a URL,
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // which prevents us from appending to the command line directly (issue
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // 46182). We therefore use GetSwitches to copy the command line (it stops
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // at the switch argument terminator).
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CommandLine old_cl(*CommandLine::ForCurrentProcess());
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<CommandLine> new_cl(new CommandLine(old_cl.GetProgram()));
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::map<std::string, CommandLine::StringType> switches =
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        old_cl.GetSwitches();
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Append the old switches to the new command line.
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (std::map<std::string, CommandLine::StringType>::const_iterator i =
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        switches.begin(); i != switches.end(); ++i) {
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CommandLine::StringType switch_value = i->second;
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!switch_value.empty())
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_cl->AppendSwitchWithValue(i->first, i->second);
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      else
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_cl->AppendSwitch(i->first);
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Ensure restore last session is set.
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!new_cl->HasSwitch(switches::kRestoreLastSession))
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_cl->AppendSwitch(switches::kRestoreLastSession);
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) || defined(OS_LINUX)
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Upgrade::RelaunchChromeBrowser(*new_cl.get());
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // defined(OS_WIN) || defined(OS_LINUX)
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX)
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_cl->AppendSwitch(switches::kActivateOnLaunch);
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::LaunchApp(*new_cl.get(), false, false, NULL);
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // defined(OS_MACOSX)
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTIMPLEMENTED();
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // !defined(OS_CHROMEOS)
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (shutdown_type_ > NOT_VALID && shutdown_num_processes_ > 0) {
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Measure total shutdown time as late in the process as possible
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // and then write it to a file to be read at startup.
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We can't use prefs since all services are shutdown at this point.
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TimeDelta shutdown_delta = Time::Now() - shutdown_started_;
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string shutdown_ms = Int64ToString(shutdown_delta.InMilliseconds());
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int len = static_cast<int>(shutdown_ms.length()) + 1;
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FilePath shutdown_ms_file = GetShutdownMsPath();
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    file_util::WriteFile(shutdown_ms_file, shutdown_ms.c_str(), len);
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UnregisterURLRequestChromeJob();
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ReadLastShutdownFile(
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ShutdownType type,
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int num_procs,
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int num_procs_slow) {
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath shutdown_ms_file = GetShutdownMsPath();
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string shutdown_ms_str;
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 shutdown_ms = 0;
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (file_util::ReadFileToString(shutdown_ms_file, &shutdown_ms_str))
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    shutdown_ms = StringToInt64(shutdown_ms_str);
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  file_util::Delete(shutdown_ms_file, false);
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type == NOT_VALID || shutdown_ms == 0 || num_procs == 0)
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char *time_fmt = "Shutdown.%s.time";
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char *time_per_fmt = "Shutdown.%s.time_per_process";
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string time;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string time_per;
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type == WINDOW_CLOSE) {
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    time = StringPrintf(time_fmt, "window_close");
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    time_per = StringPrintf(time_per_fmt, "window_close");
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type == BROWSER_EXIT) {
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    time = StringPrintf(time_fmt, "browser_exit");
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    time_per = StringPrintf(time_per_fmt, "browser_exit");
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (type == END_SESSION) {
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    time = StringPrintf(time_fmt, "end_session");
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    time_per = StringPrintf(time_per_fmt, "end_session");
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (time.empty())
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(erikkay): change these to UMA histograms after a bit more testing.
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_TIMES(time.c_str(),
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      TimeDelta::FromMilliseconds(shutdown_ms));
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_TIMES(time_per.c_str(),
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      TimeDelta::FromMilliseconds(shutdown_ms / num_procs));
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS_100("Shutdown.renderers.total", num_procs);
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS_100("Shutdown.renderers.slow", num_procs_slow);
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ReadLastShutdownInfo() {
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PrefService* prefs = g_browser_process->local_state();
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ShutdownType type =
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      static_cast<ShutdownType>(prefs->GetInteger(prefs::kShutdownType));
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int num_procs = prefs->GetInteger(prefs::kShutdownNumProcesses);
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int num_procs_slow = prefs->GetInteger(prefs::kShutdownNumProcessesSlow);
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // clear the prefs immediately so we don't pick them up on a future run
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->SetInteger(prefs::kShutdownType, NOT_VALID);
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->SetInteger(prefs::kShutdownNumProcesses, 0);
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->SetInteger(prefs::kShutdownNumProcessesSlow, 0);
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Read and delete the file on the file thread.
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ChromeThread::PostTask(
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ChromeThread::FILE, FROM_HERE,
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableFunction(
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &ReadLastShutdownFile, type, num_procs, num_procs_slow));
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SetTryingToQuit(bool quitting) {
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_trying_to_quit = quitting;
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool IsTryingToQuit() {
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return g_trying_to_quit;
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_shutdown
291