| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/lifetime/application_lifetime.h" | 5 #include "chrome/browser/lifetime/application_lifetime_desktop.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/logging.h" | 7 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" | |
| 11 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 12 #include "base/prefs/pref_service.h" | 9 #include "base/prefs/pref_service.h" |
| 13 #include "base/process/process.h" | 10 #include "base/process/process.h" |
| 14 #include "base/process/process_handle.h" | 11 #include "base/process/process_handle.h" |
| 15 #include "base/trace_event/trace_event.h" | 12 #include "base/trace_event/trace_event.h" |
| 16 #include "build/build_config.h" | |
| 17 #include "chrome/browser/browser_process.h" | 13 #include "chrome/browser/browser_process.h" |
| 18 #include "chrome/browser/browser_process_platform_part.h" | |
| 19 #include "chrome/browser/browser_shutdown.h" | 14 #include "chrome/browser/browser_shutdown.h" |
| 20 #include "chrome/browser/chrome_notification_types.h" | |
| 21 #include "chrome/browser/download/download_service.h" | 15 #include "chrome/browser/download/download_service.h" |
| 16 #include "chrome/browser/lifetime/application_lifetime.h" |
| 17 #include "chrome/browser/lifetime/application_lifetime_internal.h" |
| 22 #include "chrome/browser/lifetime/browser_close_manager.h" | 18 #include "chrome/browser/lifetime/browser_close_manager.h" |
| 23 #include "chrome/browser/metrics/thread_watcher.h" | 19 #include "chrome/browser/metrics/thread_watcher.h" |
| 24 #include "chrome/browser/profiles/profile.h" | 20 #include "chrome/browser/profiles/profile.h" |
| 25 #include "chrome/browser/profiles/profile_manager.h" | 21 #include "chrome/browser/profiles/profile_manager.h" |
| 26 #include "chrome/browser/ui/browser.h" | 22 #include "chrome/browser/ui/browser.h" |
| 27 #include "chrome/browser/ui/browser_finder.h" | 23 #include "chrome/browser/ui/browser_finder.h" |
| 28 #include "chrome/browser/ui/browser_iterator.h" | 24 #include "chrome/browser/ui/browser_iterator.h" |
| 29 #include "chrome/browser/ui/browser_tabstrip.h" | |
| 30 #include "chrome/browser/ui/browser_window.h" | 25 #include "chrome/browser/ui/browser_window.h" |
| 31 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
| 32 #include "chrome/browser/ui/user_manager.h" | 26 #include "chrome/browser/ui/user_manager.h" |
| 33 #include "chrome/common/chrome_constants.h" | 27 #include "chrome/common/chrome_constants.h" |
| 34 #include "chrome/common/chrome_switches.h" | |
| 35 #include "chrome/common/pref_names.h" | 28 #include "chrome/common/pref_names.h" |
| 36 #include "components/tracing/tracing_switches.h" | |
| 37 #include "content/public/browser/browser_thread.h" | |
| 38 #include "content/public/browser/navigation_details.h" | |
| 39 #include "content/public/browser/notification_service.h" | |
| 40 | 29 |
| 41 #if defined(OS_CHROMEOS) | 30 #if defined(OS_CHROMEOS) |
| 31 #include "base/bind.h" |
| 42 #include "base/sys_info.h" | 32 #include "base/sys_info.h" |
| 43 #include "chrome/browser/chromeos/boot_times_recorder.h" | 33 #include "chrome/browser/chromeos/boot_times_recorder.h" |
| 44 #include "chromeos/dbus/dbus_thread_manager.h" | 34 #include "chromeos/dbus/dbus_thread_manager.h" |
| 45 #include "chromeos/dbus/session_manager_client.h" | 35 #include "chromeos/dbus/session_manager_client.h" |
| 46 #include "chromeos/dbus/update_engine_client.h" | 36 #include "chromeos/dbus/update_engine_client.h" |
| 37 #include "content/public/browser/browser_thread.h" |
| 47 #endif | 38 #endif |
| 48 | 39 |
| 49 #if defined(OS_WIN) | 40 #if defined(OS_WIN) |
| 41 #include "ash/shell.h" |
| 50 #include "base/win/win_util.h" | 42 #include "base/win/win_util.h" |
| 51 #include "components/browser_watcher/exit_funnel_win.h" | |
| 52 #endif | |
| 53 | |
| 54 #if defined(USE_ASH) | |
| 55 #include "ash/shell.h" | |
| 56 #endif | 43 #endif |
| 57 | 44 |
| 58 namespace chrome { | 45 namespace chrome { |
| 46 |
| 59 namespace { | 47 namespace { |
| 60 | 48 |
| 61 #if !defined(OS_ANDROID) | |
| 62 // Returns true if all browsers can be closed without user interaction. | 49 // Returns true if all browsers can be closed without user interaction. |
| 63 // This currently checks if there is pending download, or if it needs to | 50 // This currently checks if there is pending download, or if it needs to |
| 64 // handle unload handler. | 51 // handle unload handler. |
| 65 bool AreAllBrowsersCloseable() { | 52 bool AreAllBrowsersCloseable() { |
| 66 chrome::BrowserIterator browser_it; | 53 chrome::BrowserIterator browser_it; |
| 67 if (browser_it.done()) | 54 if (browser_it.done()) |
| 68 return true; | 55 return true; |
| 69 | 56 |
| 70 // If there are any downloads active, all browsers are not closeable. | 57 // If there are any downloads active, all browsers are not closeable. |
| 71 // However, this does not block for malicious downloads. | 58 // However, this does not block for malicious downloads. |
| 72 if (DownloadService::NonMaliciousDownloadCountAllProfiles() > 0) | 59 if (DownloadService::NonMaliciousDownloadCountAllProfiles() > 0) |
| 73 return false; | 60 return false; |
| 74 | 61 |
| 75 // Check TabsNeedBeforeUnloadFired(). | 62 // Check TabsNeedBeforeUnloadFired(). |
| 76 for (; !browser_it.done(); browser_it.Next()) { | 63 for (; !browser_it.done(); browser_it.Next()) { |
| 77 if (browser_it->TabsNeedBeforeUnloadFired()) | 64 if (browser_it->TabsNeedBeforeUnloadFired()) |
| 78 return false; | 65 return false; |
| 79 } | 66 } |
| 80 return true; | 67 return true; |
| 81 } | 68 } |
| 82 #endif // !defined(OS_ANDROID) | |
| 83 | 69 |
| 84 int g_keep_alive_count = 0; | 70 int g_keep_alive_count = 0; |
| 85 bool g_disable_shutdown_for_testing = false; | 71 bool g_disable_shutdown_for_testing = false; |
| 86 | 72 |
| 87 #if defined(OS_CHROMEOS) | 73 #if defined(OS_CHROMEOS) |
| 88 // Whether chrome should send stop request to a session manager. | 74 // Whether chrome should send stop request to a session manager. |
| 89 bool g_send_stop_request_to_session_manager = false; | 75 bool g_send_stop_request_to_session_manager = false; |
| 90 #endif | 76 #endif |
| 91 | 77 |
| 92 } // namespace | |
| 93 | |
| 94 void MarkAsCleanShutdown() { | 78 void MarkAsCleanShutdown() { |
| 95 // TODO(beng): Can this use ProfileManager::GetLoadedProfiles() instead? | 79 // TODO(beng): Can this use ProfileManager::GetLoadedProfiles() instead? |
| 96 for (chrome::BrowserIterator it; !it.done(); it.Next()) | 80 for (chrome::BrowserIterator it; !it.done(); it.Next()) |
| 97 it->profile()->SetExitType(Profile::EXIT_NORMAL); | 81 it->profile()->SetExitType(Profile::EXIT_NORMAL); |
| 98 } | 82 } |
| 99 | 83 |
| 100 void AttemptExitInternal(bool try_to_quit_application) { | 84 void CloseAllBrowsersIfNeeded() { |
| 101 // On Mac, the platform-specific part handles setting this. | 85 // If there are no browsers open and we aren't already shutting down, |
| 102 #if !defined(OS_MACOSX) | 86 // initiate a shutdown. Also skips shutdown if this is a unit test. |
| 103 if (try_to_quit_application) | 87 // (MessageLoop::current() == null or explicitly disabled). |
| 104 browser_shutdown::SetTryingToQuit(true); | 88 if (chrome::GetTotalBrowserCount() == 0 && |
| 89 !browser_shutdown::IsTryingToQuit() && base::MessageLoop::current() && |
| 90 !g_disable_shutdown_for_testing) { |
| 91 CloseAllBrowsers(); |
| 92 } |
| 93 } |
| 94 |
| 95 } // namespace |
| 96 |
| 97 namespace internal { |
| 98 |
| 99 #if defined(OS_CHROMEOS) |
| 100 void NotifyAndTerminateInternalCrOS() { |
| 101 if (base::SysInfo::IsRunningOnChromeOS()) { |
| 102 // If we're on a ChromeOS device, reboot if an update has been applied, |
| 103 // or else signal the session manager to log out. |
| 104 chromeos::UpdateEngineClient* update_engine_client |
| 105 = chromeos::DBusThreadManager::Get()->GetUpdateEngineClient(); |
| 106 if (update_engine_client->GetLastStatus().status == |
| 107 chromeos::UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) { |
| 108 update_engine_client->RebootAfterUpdate(); |
| 109 } else if (g_send_stop_request_to_session_manager) { |
| 110 // Don't ask SessionManager to stop session if the shutdown request comes |
| 111 // from session manager. |
| 112 chromeos::DBusThreadManager::Get()->GetSessionManagerClient() |
| 113 ->StopSession(); |
| 114 } |
| 115 } else { |
| 116 if (g_send_stop_request_to_session_manager) { |
| 117 // If running the Chrome OS build, but we're not on the device, act |
| 118 // as if we received signal from SessionManager. |
| 119 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
| 120 base::Bind(&ExitCleanly)); |
| 121 } |
| 122 } |
| 123 } |
| 124 #else |
| 125 void AttemptExitInternalDesktop() { |
| 126 if (AreAllBrowsersCloseable()) |
| 127 MarkAsCleanShutdown(); |
| 128 } |
| 105 #endif | 129 #endif |
| 106 | 130 |
| 107 content::NotificationService::current()->Notify( | 131 } // namespace internal |
| 108 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, | |
| 109 content::NotificationService::AllSources(), | |
| 110 content::NotificationService::NoDetails()); | |
| 111 | |
| 112 g_browser_process->platform_part()->AttemptExit(); | |
| 113 } | |
| 114 | 132 |
| 115 void CloseAllBrowsersAndQuit() { | 133 void CloseAllBrowsersAndQuit() { |
| 116 browser_shutdown::SetTryingToQuit(true); | 134 browser_shutdown::SetTryingToQuit(true); |
| 117 CloseAllBrowsers(); | 135 CloseAllBrowsers(); |
| 118 } | 136 } |
| 119 | 137 |
| 120 void CloseAllBrowsers() { | 138 void CloseAllBrowsers() { |
| 121 // If there are no browsers and closing the last browser would quit the | 139 // If there are no browsers and closing the last browser would quit the |
| 122 // application, send the APP_TERMINATING action here. Otherwise, it will be | 140 // application, send the APP_TERMINATING action here. Otherwise, it will be |
| 123 // sent by RemoveBrowser() when the last browser has closed. | 141 // sent by RemoveBrowser() when the last browser has closed. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 g_send_stop_request_to_session_manager = true; | 188 g_send_stop_request_to_session_manager = true; |
| 171 // On ChromeOS, always terminate the browser, regardless of the result of | 189 // On ChromeOS, always terminate the browser, regardless of the result of |
| 172 // AreAllBrowsersCloseable(). See crbug.com/123107. | 190 // AreAllBrowsersCloseable(). See crbug.com/123107. |
| 173 chrome::NotifyAndTerminate(true); | 191 chrome::NotifyAndTerminate(true); |
| 174 #else | 192 #else |
| 175 // Reset the restart bit that might have been set in cancelled restart | 193 // Reset the restart bit that might have been set in cancelled restart |
| 176 // request. | 194 // request. |
| 177 UserManager::Hide(); | 195 UserManager::Hide(); |
| 178 PrefService* pref_service = g_browser_process->local_state(); | 196 PrefService* pref_service = g_browser_process->local_state(); |
| 179 pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, false); | 197 pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, false); |
| 180 AttemptExitInternal(false); | 198 internal::AttemptExitInternal(false); |
| 181 #endif | 199 #endif // defined(OS_CHROMEOS) |
| 182 } | |
| 183 | |
| 184 void StartShutdownTracing() { | |
| 185 const base::CommandLine& command_line = | |
| 186 *base::CommandLine::ForCurrentProcess(); | |
| 187 if (command_line.HasSwitch(switches::kTraceShutdown)) { | |
| 188 base::trace_event::TraceConfig trace_config( | |
| 189 command_line.GetSwitchValueASCII(switches::kTraceShutdown), ""); | |
| 190 base::trace_event::TraceLog::GetInstance()->SetEnabled( | |
| 191 trace_config, | |
| 192 base::trace_event::TraceLog::RECORDING_MODE); | |
| 193 } | |
| 194 TRACE_EVENT0("shutdown", "StartShutdownTracing"); | |
| 195 } | 200 } |
| 196 | 201 |
| 197 // The Android implementation is in application_lifetime_android.cc | 202 // The Android implementation is in application_lifetime_android.cc |
| 198 #if !defined(OS_ANDROID) | |
| 199 void AttemptRestart() { | 203 void AttemptRestart() { |
| 200 // TODO(beng): Can this use ProfileManager::GetLoadedProfiles instead? | 204 // TODO(beng): Can this use ProfileManager::GetLoadedProfiles instead? |
| 201 for (chrome::BrowserIterator it; !it.done(); it.Next()) | 205 for (chrome::BrowserIterator it; !it.done(); it.Next()) |
| 202 content::BrowserContext::SaveSessionState(it->profile()); | 206 content::BrowserContext::SaveSessionState(it->profile()); |
| 203 | 207 |
| 204 PrefService* pref_service = g_browser_process->local_state(); | 208 PrefService* pref_service = g_browser_process->local_state(); |
| 205 pref_service->SetBoolean(prefs::kWasRestarted, true); | 209 pref_service->SetBoolean(prefs::kWasRestarted, true); |
| 206 | 210 |
| 207 #if defined(OS_CHROMEOS) | 211 #if defined(OS_CHROMEOS) |
| 208 chromeos::BootTimesRecorder::Get()->set_restart_requested(); | 212 chromeos::BootTimesRecorder::Get()->set_restart_requested(); |
| 209 | 213 |
| 210 DCHECK(!g_send_stop_request_to_session_manager); | 214 DCHECK(!g_send_stop_request_to_session_manager); |
| 211 // Make sure we don't send stop request to the session manager. | 215 // Make sure we don't send stop request to the session manager. |
| 212 g_send_stop_request_to_session_manager = false; | 216 g_send_stop_request_to_session_manager = false; |
| 213 // Run exit process in clean stack. | 217 // Run exit process in clean stack. |
| 214 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 218 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
| 215 base::Bind(&ExitCleanly)); | 219 base::Bind(&ExitCleanly)); |
| 216 #else | 220 #else |
| 217 // Set the flag to restore state after the restart. | 221 // Set the flag to restore state after the restart. |
| 218 pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true); | 222 pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true); |
| 219 AttemptExit(); | 223 AttemptExit(); |
| 220 #endif | 224 #endif |
| 221 } | 225 } |
| 222 #endif | |
| 223 | |
| 224 void AttemptExit() { | |
| 225 #if defined(OS_CHROMEOS) | |
| 226 // On ChromeOS, user exit and system exits are the same. | |
| 227 AttemptUserExit(); | |
| 228 #else | |
| 229 // If we know that all browsers can be closed without blocking, | |
| 230 // don't notify users of crashes beyond this point. | |
| 231 // Note that MarkAsCleanShutdown() does not set UMA's exit cleanly bit | |
| 232 // so crashes during shutdown are still reported in UMA. | |
| 233 #if !defined(OS_ANDROID) | |
| 234 // Android doesn't use Browser. | |
| 235 if (AreAllBrowsersCloseable()) | |
| 236 MarkAsCleanShutdown(); | |
| 237 #endif | |
| 238 AttemptExitInternal(true); | |
| 239 #endif | |
| 240 } | |
| 241 | 226 |
| 242 #if defined(OS_CHROMEOS) | 227 #if defined(OS_CHROMEOS) |
| 243 // A function called when SIGTERM is received. | 228 // A function called when SIGTERM is received. |
| 244 void ExitCleanly() { | 229 void ExitCleanly() { |
| 245 // We always mark exit cleanly. | 230 // We always mark exit cleanly. |
| 246 MarkAsCleanShutdown(); | 231 MarkAsCleanShutdown(); |
| 247 | 232 |
| 248 // Don't block when SIGTERM is received. AreaAllBrowsersCloseable() | 233 // Don't block when SIGTERM is received. AreaAllBrowsersCloseable() |
| 249 // can be false in following cases. a) power-off b) signout from | 234 // can be false in following cases. a) power-off b) signout from |
| 250 // screen locker. | 235 // screen locker. |
| 251 if (!AreAllBrowsersCloseable()) | 236 if (!AreAllBrowsersCloseable()) |
| 252 browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION); | 237 browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION); |
| 253 else | 238 else |
| 254 browser_shutdown::OnShutdownStarting(browser_shutdown::BROWSER_EXIT); | 239 browser_shutdown::OnShutdownStarting(browser_shutdown::BROWSER_EXIT); |
| 255 AttemptExitInternal(true); | 240 internal::AttemptExitInternal(true); |
| 256 } | 241 } |
| 257 #endif | 242 #endif |
| 258 | 243 |
| 259 void SessionEnding() { | |
| 260 #if defined(OS_WIN) | |
| 261 browser_watcher::ExitFunnel funnel; | |
| 262 | |
| 263 funnel.Init(kBrowserExitCodesRegistryPath, base::GetCurrentProcessHandle()); | |
| 264 funnel.RecordEvent(L"SessionEnding"); | |
| 265 #endif | |
| 266 // This is a time-limited shutdown where we need to write as much to | |
| 267 // disk as we can as soon as we can, and where we must kill the | |
| 268 // process within a hang timeout to avoid user prompts. | |
| 269 | |
| 270 // Start watching for hang during shutdown, and crash it if takes too long. | |
| 271 // We disarm when |shutdown_watcher| object is destroyed, which is when we | |
| 272 // exit this function. | |
| 273 ShutdownWatcherHelper shutdown_watcher; | |
| 274 shutdown_watcher.Arm(base::TimeDelta::FromSeconds(90)); | |
| 275 | |
| 276 // EndSession is invoked once per frame. Only do something the first time. | |
| 277 static bool already_ended = false; | |
| 278 // We may get called in the middle of shutdown, e.g. http://crbug.com/70852 | |
| 279 // In this case, do nothing. | |
| 280 if (already_ended || !content::NotificationService::current()) | |
| 281 return; | |
| 282 already_ended = true; | |
| 283 | |
| 284 browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION); | |
| 285 | |
| 286 content::NotificationService::current()->Notify( | |
| 287 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, | |
| 288 content::NotificationService::AllSources(), | |
| 289 content::NotificationService::NoDetails()); | |
| 290 | |
| 291 #if defined(OS_WIN) | |
| 292 funnel.RecordEvent(L"EndSession"); | |
| 293 #endif | |
| 294 // Write important data first. | |
| 295 g_browser_process->EndSession(); | |
| 296 | |
| 297 #if defined(OS_WIN) | |
| 298 base::win::SetShouldCrashOnProcessDetach(false); | |
| 299 #endif | |
| 300 | |
| 301 #if defined(OS_WIN) | |
| 302 // KillProcess ought to terminate the process without further ado, so if | |
| 303 // execution gets to this point, presumably this is normal exit. | |
| 304 funnel.RecordEvent(L"KillProcess"); | |
| 305 #endif | |
| 306 | |
| 307 // On Windows 7 and later, the system will consider the process ripe for | |
| 308 // termination as soon as it hides or destroys its windows. Since any | |
| 309 // execution past that point will be non-deterministically cut short, we | |
| 310 // might as well put ourselves out of that misery deterministically. | |
| 311 base::Process::Current().Terminate(0, false); | |
| 312 } | |
| 313 | |
| 314 void IncrementKeepAliveCount() { | 244 void IncrementKeepAliveCount() { |
| 315 // Increment the browser process refcount as long as we're keeping the | 245 // Increment the browser process refcount as long as we're keeping the |
| 316 // application alive. | 246 // application alive. |
| 317 if (!WillKeepAlive()) | 247 if (!WillKeepAlive()) |
| 318 g_browser_process->AddRefModule(); | 248 g_browser_process->AddRefModule(); |
| 319 ++g_keep_alive_count; | 249 ++g_keep_alive_count; |
| 320 } | 250 } |
| 321 | 251 |
| 322 void CloseAllBrowsersIfNeeded() { | |
| 323 // If there are no browsers open and we aren't already shutting down, | |
| 324 // initiate a shutdown. Also skips shutdown if this is a unit test. | |
| 325 // (MessageLoop::current() == null or explicitly disabled). | |
| 326 if (chrome::GetTotalBrowserCount() == 0 && | |
| 327 !browser_shutdown::IsTryingToQuit() && base::MessageLoop::current() && | |
| 328 !g_disable_shutdown_for_testing) { | |
| 329 CloseAllBrowsers(); | |
| 330 } | |
| 331 } | |
| 332 | |
| 333 void DecrementKeepAliveCount() { | 252 void DecrementKeepAliveCount() { |
| 334 DCHECK_GT(g_keep_alive_count, 0); | 253 DCHECK_GT(g_keep_alive_count, 0); |
| 335 --g_keep_alive_count; | 254 --g_keep_alive_count; |
| 336 // Although we should have a browser process, if there is none, | 255 // Although we should have a browser process, if there is none, |
| 337 // there is nothing to do. | 256 // there is nothing to do. |
| 338 if (!g_browser_process) return; | 257 if (!g_browser_process) return; |
| 339 | 258 |
| 340 // Allow the app to shutdown again. | 259 // Allow the app to shutdown again. |
| 341 if (!WillKeepAlive()) { | 260 if (!WillKeepAlive()) { |
| 342 g_browser_process->ReleaseModule(); | 261 g_browser_process->ReleaseModule(); |
| 343 CloseAllBrowsersIfNeeded(); | 262 CloseAllBrowsersIfNeeded(); |
| 344 } | 263 } |
| 345 } | 264 } |
| 346 | 265 |
| 347 bool WillKeepAlive() { | 266 bool WillKeepAlive() { |
| 348 return g_keep_alive_count > 0; | 267 return g_keep_alive_count > 0; |
| 349 } | 268 } |
| 350 | 269 |
| 351 void NotifyAppTerminating() { | |
| 352 static bool notified = false; | |
| 353 if (notified) | |
| 354 return; | |
| 355 notified = true; | |
| 356 content::NotificationService::current()->Notify( | |
| 357 chrome::NOTIFICATION_APP_TERMINATING, | |
| 358 content::NotificationService::AllSources(), | |
| 359 content::NotificationService::NoDetails()); | |
| 360 } | |
| 361 | |
| 362 void NotifyAndTerminate(bool fast_path) { | |
| 363 #if defined(OS_CHROMEOS) | |
| 364 static bool notified = false; | |
| 365 // Return if a shutdown request has already been sent. | |
| 366 if (notified) | |
| 367 return; | |
| 368 notified = true; | |
| 369 #endif | |
| 370 | |
| 371 if (fast_path) | |
| 372 NotifyAppTerminating(); | |
| 373 | |
| 374 #if defined(OS_CHROMEOS) | |
| 375 if (base::SysInfo::IsRunningOnChromeOS()) { | |
| 376 // If we're on a ChromeOS device, reboot if an update has been applied, | |
| 377 // or else signal the session manager to log out. | |
| 378 chromeos::UpdateEngineClient* update_engine_client | |
| 379 = chromeos::DBusThreadManager::Get()->GetUpdateEngineClient(); | |
| 380 if (update_engine_client->GetLastStatus().status == | |
| 381 chromeos::UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) { | |
| 382 update_engine_client->RebootAfterUpdate(); | |
| 383 } else if (g_send_stop_request_to_session_manager) { | |
| 384 // Don't ask SessionManager to stop session if the shutdown request comes | |
| 385 // from session manager. | |
| 386 chromeos::DBusThreadManager::Get()->GetSessionManagerClient() | |
| 387 ->StopSession(); | |
| 388 } | |
| 389 } else { | |
| 390 if (g_send_stop_request_to_session_manager) { | |
| 391 // If running the Chrome OS build, but we're not on the device, act | |
| 392 // as if we received signal from SessionManager. | |
| 393 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | |
| 394 base::Bind(&ExitCleanly)); | |
| 395 } | |
| 396 } | |
| 397 #endif | |
| 398 } | |
| 399 | |
| 400 void OnAppExiting() { | 270 void OnAppExiting() { |
| 401 static bool notified = false; | 271 static bool notified = false; |
| 402 if (notified) | 272 if (notified) |
| 403 return; | 273 return; |
| 404 notified = true; | 274 notified = true; |
| 405 HandleAppExitingForPlatform(); | 275 HandleAppExitingForPlatform(); |
| 406 } | 276 } |
| 407 | 277 |
| 408 bool ShouldStartShutdown(Browser* browser) { | 278 bool ShouldStartShutdown(Browser* browser) { |
| 409 if (BrowserList::GetInstance(browser->host_desktop_type())->size() > 1) | 279 if (BrowserList::GetInstance(browser->host_desktop_type())->size() > 1) |
| 410 return false; | 280 return false; |
| 411 #if defined(OS_WIN) | 281 #if defined(OS_WIN) |
| 412 // On Windows 8 the desktop and ASH environments could be active | 282 // On Windows 8 the desktop and ASH environments could be active |
| 413 // at the same time. | 283 // at the same time. |
| 414 // We should not start the shutdown process in the following cases:- | 284 // We should not start the shutdown process in the following cases:- |
| 415 // 1. If the desktop type of the browser going away is ASH and there | 285 // 1. If the desktop type of the browser going away is ASH and there |
| 416 // are browser windows open in the desktop. | 286 // are browser windows open in the desktop. |
| 417 // 2. If the desktop type of the browser going away is desktop and the ASH | 287 // 2. If the desktop type of the browser going away is desktop and the ASH |
| 418 // environment is still active. | 288 // environment is still active. |
| 419 if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_NATIVE) | 289 if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_NATIVE) |
| 420 return !ash::Shell::HasInstance(); | 290 return !ash::Shell::HasInstance(); |
| 421 else if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) | 291 else if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) |
| 422 return BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE)->empty(); | 292 return BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE)->empty(); |
| 423 #endif | 293 #endif // defined(OS_WIN) |
| 424 return true; | 294 return true; |
| 425 } | 295 } |
| 426 | 296 |
| 427 void DisableShutdownForTesting(bool disable_shutdown_for_testing) { | 297 void DisableShutdownForTesting(bool disable_shutdown_for_testing) { |
| 428 g_disable_shutdown_for_testing = disable_shutdown_for_testing; | 298 g_disable_shutdown_for_testing = disable_shutdown_for_testing; |
| 429 if (!g_disable_shutdown_for_testing && !WillKeepAlive()) | 299 if (!g_disable_shutdown_for_testing && !WillKeepAlive()) |
| 430 CloseAllBrowsersIfNeeded(); | 300 CloseAllBrowsersIfNeeded(); |
| 431 } | 301 } |
| 432 | 302 |
| 433 } // namespace chrome | 303 } // namespace chrome |
| OLD | NEW |