1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 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 772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <map> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string> 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/command_line.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_path.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 13731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/process_util.h" 163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/synchronization/waitable_event.h" 193f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h" 203f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_restrictions.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h" 23731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/about_flags.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h" 25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/first_run/upgrade_util.h" 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/jankometer.h" 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/metrics_service.h" 283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h" 2921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile_manager.h" 30731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/service/service_process_control_manager.h" 3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/browser_list.h" 32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/webui/chrome_url_data_manager.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h" 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h" 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h" 363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/switch_utils.h" 37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h" 38dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/plugin_process_host.h" 39dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_process_host.h" 40dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h" 41dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_widget_host.h" 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/predictor_api.h" 4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h" 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/browser_util_win.h" 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/first_run/upgrade_util_win.h" 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/rlz/rlz.h" 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 51201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#if defined(OS_CHROMEOS) 52201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/browser/chromeos/boot_times_loader.h" 5321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/chromeos/cros/cros_library.h" 5421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/chromeos/cros/login_library.h" 5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/chromeos/system_key_event_listener.h" 56201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#endif 57201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time; 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta; 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_shutdown { 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Whether the browser is trying to quit (e.g., Quit chosen from menu). 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool g_trying_to_quit = false; 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTime shutdown_started_; 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochShutdownType shutdown_type_ = NOT_VALID; 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint shutdown_num_processes_; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint shutdown_num_processes_slow_; 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool delete_resources_on_shutdown = true; 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kShutdownMsFile[] = "chrome_shutdown_ms.txt"; 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid RegisterPrefs(PrefService* local_state) { 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch local_state->RegisterIntegerPref(prefs::kShutdownType, NOT_VALID); 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch local_state->RegisterIntegerPref(prefs::kShutdownNumProcesses, 0); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch local_state->RegisterIntegerPref(prefs::kShutdownNumProcessesSlow, 0); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochShutdownType GetShutdownType() { 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return shutdown_type_; 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid OnShutdownStarting(ShutdownType type) { 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (shutdown_type_ != NOT_VALID) 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shutdown_type_ = type; 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For now, we're only counting the number of renderer processes 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // since we can't safely count the number of plugin processes from this 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // thread, and we'd really like to avoid anything which might add further 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // delays to shutdown time. 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shutdown_started_ = Time::Now(); 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Call FastShutdown on all of the RenderProcessHosts. This will be 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a no-op in some cases, so we still need to go through the normal 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // shutdown path for the ones that didn't exit here. 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shutdown_num_processes_ = 0; 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shutdown_num_processes_slow_ = 0; 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !i.IsAtEnd(); i.Advance()) { 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++shutdown_num_processes_; 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!i.GetCurrentValue()->FastShutdownIfPossible()) 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++shutdown_num_processes_slow_; 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath GetShutdownMsPath() { 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath shutdown_ms_file; 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PathService::Get(chrome::DIR_USER_DATA, &shutdown_ms_file); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return shutdown_ms_file.AppendASCII(kShutdownMsFile); 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid Shutdown() { 116201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#if defined(OS_CHROMEOS) 117201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker( 118201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch "BrowserShutdownStarted", false); 119201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#endif 120513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // During shutdown we will end up some blocking operations. But the 121513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // work needs to get done and we're going to wait for them no matter 122513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // what thread they're on, so don't worry about it slowing down 123513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // shutdown. 124513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::ThreadRestrictions::SetIOAllowed(true); 125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Shutdown all IPC channels to service processes. 12721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ServiceProcessControlManager::GetInstance()->Shutdown(); 128731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_CHROMEOS) 13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // The system key event listener needs to be shut down earlier than when 13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Singletons are finally destroyed in AtExitManager. 13272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen chromeos::SystemKeyEventListener::GetInstance()->Stop(); 13372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif 13472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // WARNING: During logoff/shutdown (WM_ENDSESSION) we may not have enough 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // time to get here. If you have something that *must* happen on end session, 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // consider putting it in BrowserProcessImpl::EndSession. 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(g_browser_process); 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Notifies we are going away. 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_browser_process->shutdown_event()->Signal(); 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrefService* prefs = g_browser_process->local_state(); 14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ProfileManager* profile_manager = g_browser_process->profile_manager(); 14521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen PrefService* user_prefs = profile_manager->GetDefaultProfile()->GetPrefs(); 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 14721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen chrome_browser_net::SavePredictorStateForNextStartupAndTrim(user_prefs); 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MetricsService* metrics = g_browser_process->metrics_service(); 150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (metrics) 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch metrics->RecordCompletedSessionEnd(); 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (shutdown_type_ > NOT_VALID && shutdown_num_processes_ > 0) { 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Record the shutdown info so that we can put it into a histogram at next 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // startup. 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->SetInteger(prefs::kShutdownType, shutdown_type_); 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->SetInteger(prefs::kShutdownNumProcesses, shutdown_num_processes_); 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->SetInteger(prefs::kShutdownNumProcessesSlow, 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shutdown_num_processes_slow_); 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check local state for the restart flag so we can restart the session below. 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool restart_last_session = false; 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (prefs->HasPrefPath(prefs::kRestartLastSessionOnShutdown)) { 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch restart_last_session = 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->GetBoolean(prefs::kRestartLastSessionOnShutdown); 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->ClearPref(prefs::kRestartLastSessionOnShutdown); 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->SavePersistentPrefs(); 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Cleanup any statics created by RLZ. Must be done before NotificationService 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // is destroyed. 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RLZTracker::CleanupRlz(); 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The jank'o'meter requires that the browser process has been destroyed 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // before calling UninstallJankometer(). 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete g_browser_process; 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_browser_process = NULL; 182201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#if defined(OS_CHROMEOS) 183201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("BrowserDeleted", 184201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch true); 185201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#endif 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Uninstall Jank-O-Meter here after the IO thread is no longer running. 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UninstallJankometer(); 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (delete_resources_on_shutdown) 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResourceBundle::CleanupSharedInstance(); 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!browser_util::IsBrowserAlreadyRunning() && 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shutdown_type_ != browser_shutdown::END_SESSION) { 196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen upgrade_util::SwapNewChromeExeIfPresent(); 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (restart_last_session) { 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if !defined(OS_CHROMEOS) 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure to relaunch the browser with the original command line plus 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the Restore Last Session flag. Note that Chrome can be launched (ie. 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // through ShellExecute on Windows) with a switch argument terminator at 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the end (double dash, as described in b/1366444) plus a URL, 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // which prevents us from appending to the command line directly (issue 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 46182). We therefore use GetSwitches to copy the command line (it stops 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // at the switch argument terminator). 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CommandLine old_cl(*CommandLine::ForCurrentProcess()); 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<CommandLine> new_cl(new CommandLine(old_cl.GetProgram())); 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::map<std::string, CommandLine::StringType> switches = 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch old_cl.GetSwitches(); 2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Remove the switches that shouldn't persist across restart. 214731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick about_flags::RemoveFlagsSwitches(&switches); 2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick switches::RemoveSwitchesForAutostart(&switches); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Append the old switches to the new command line. 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::map<std::string, CommandLine::StringType>::const_iterator i = 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switches.begin(); i != switches.end(); ++i) { 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CommandLine::StringType switch_value = i->second; 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!switch_value.empty()) 2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick new_cl->AppendSwitchNative(i->first, i->second); 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_cl->AppendSwitch(i->first); 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ensure restore last session is set. 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!new_cl->HasSwitch(switches::kRestoreLastSession)) 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_cl->AppendSwitch(switches::kRestoreLastSession); 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) || defined(OS_LINUX) 230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen upgrade_util::RelaunchChromeBrowser(*new_cl.get()); 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // defined(OS_WIN) || defined(OS_LINUX) 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX) 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_cl->AppendSwitch(switches::kActivateOnLaunch); 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::LaunchApp(*new_cl.get(), false, false, NULL); 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // defined(OS_MACOSX) 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTIMPLEMENTED(); 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif // !defined(OS_CHROMEOS) 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (shutdown_type_ > NOT_VALID && shutdown_num_processes_ > 0) { 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Measure total shutdown time as late in the process as possible 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and then write it to a file to be read at startup. 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We can't use prefs since all services are shutdown at this point. 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TimeDelta shutdown_delta = Time::Now() - shutdown_started_; 2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string shutdown_ms = 2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::Int64ToString(shutdown_delta.InMilliseconds()); 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int len = static_cast<int>(shutdown_ms.length()) + 1; 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath shutdown_ms_file = GetShutdownMsPath(); 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::WriteFile(shutdown_ms_file, shutdown_ms.c_str(), len); 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 25521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(OS_CHROMEOS) 25672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen BrowserList::NotifyAndTerminate(false); 25721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif 25872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ChromeURLDataManager::DeleteDataSources(); 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ReadLastShutdownFile( 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ShutdownType type, 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int num_procs, 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int num_procs_slow) { 266731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath shutdown_ms_file = GetShutdownMsPath(); 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string shutdown_ms_str; 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 shutdown_ms = 0; 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (file_util::ReadFileToString(shutdown_ms_file, &shutdown_ms_str)) 2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::StringToInt64(shutdown_ms_str, &shutdown_ms); 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::Delete(shutdown_ms_file, false); 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type == NOT_VALID || shutdown_ms == 0 || num_procs == 0) 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const char *time_fmt = "Shutdown.%s.time"; 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const char *time_per_fmt = "Shutdown.%s.time_per_process"; 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string time; 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string time_per; 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type == WINDOW_CLOSE) { 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch time = StringPrintf(time_fmt, "window_close"); 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch time_per = StringPrintf(time_per_fmt, "window_close"); 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (type == BROWSER_EXIT) { 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch time = StringPrintf(time_fmt, "browser_exit"); 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch time_per = StringPrintf(time_per_fmt, "browser_exit"); 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (type == END_SESSION) { 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch time = StringPrintf(time_fmt, "end_session"); 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch time_per = StringPrintf(time_per_fmt, "end_session"); 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (time.empty()) 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(erikkay): change these to UMA histograms after a bit more testing. 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_TIMES(time.c_str(), 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TimeDelta::FromMilliseconds(shutdown_ms)); 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_TIMES(time_per.c_str(), 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TimeDelta::FromMilliseconds(shutdown_ms / num_procs)); 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_COUNTS_100("Shutdown.renderers.total", num_procs); 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_COUNTS_100("Shutdown.renderers.slow", num_procs_slow); 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ReadLastShutdownInfo() { 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrefService* prefs = g_browser_process->local_state(); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ShutdownType type = 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<ShutdownType>(prefs->GetInteger(prefs::kShutdownType)); 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int num_procs = prefs->GetInteger(prefs::kShutdownNumProcesses); 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int num_procs_slow = prefs->GetInteger(prefs::kShutdownNumProcessesSlow); 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // clear the prefs immediately so we don't pick them up on a future run 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->SetInteger(prefs::kShutdownType, NOT_VALID); 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->SetInteger(prefs::kShutdownNumProcesses, 0); 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->SetInteger(prefs::kShutdownNumProcessesSlow, 0); 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Read and delete the file on the file thread. 319731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 320731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableFunction( 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &ReadLastShutdownFile, type, num_procs, num_procs_slow)); 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SetTryingToQuit(bool quitting) { 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_trying_to_quit = quitting; 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool IsTryingToQuit() { 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return g_trying_to_quit; 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool ShuttingDownWithoutClosingBrowsers() { 3343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(USE_X11) 3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (GetShutdownType() == browser_shutdown::END_SESSION) 3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif 3383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace browser_shutdown 342