Index: chrome/browser/ui/browser_list.cc |
diff --git a/chrome/browser/ui/browser_list.cc b/chrome/browser/ui/browser_list.cc |
index be11579dd2359840435112537ac8179c225e8e87..f05ee705ac7f0425d7b34a07cf0bc51fecd144e2 100644 |
--- a/chrome/browser/ui/browser_list.cc |
+++ b/chrome/browser/ui/browser_list.cc |
@@ -40,6 +40,95 @@ |
namespace { |
+// ********************* IMPORTANT **************** |
+// Please read and update if you need to change the quit/shutdown |
+// process. |
+// |
+// This is an attempt to descritbe different kinds of quit/shutdown |
+// process that chrome may process. This overs only Windows and Linux |
+// because I (oshima) don't know about mac. Mac contribution to this |
+// comment would be greatly appreciated. |
+// |
+// Common behavior. |
+// APP_EXITING notification is always sent when chrome starts shutdown |
+// process (with one exception. see ChromeOS guest mode below). |
+// Note that shutdown process can be canceled, so APP_EXITING may |
+// be sent MORE THAN ONCE. |
+// |
+// Normal shutdown on Linux & Windows |
+// A user requested to quit the browser (win: by wrench menu or |
+// ctrl-alt-q, or linux:wrench menu, ctrl-alt-q or SIGTERM). |
+// It notifies APP_EXITING, then tries to close all browsers. |
+// When the last browser gets deleted, it sends out APP_TERMINATING |
+// notification as a signal that browser is really quitting. |
+// Shutdown may be blocked and canceled by beforeunload handler or |
+// downloads in progress. (in which case, APP_TERMINATING won't be sent) |
+// |
+// Restart on Linux & Windows |
+// A user requested to restart the browser. This can happen when |
+// certain preference has changed (flags page, language option), or |
+// update is availabe. Chrome sets kRestartLastSessionOnShutdown |
+// preference to true, follows normal shutdown process and re-launches |
+// itself at the end of the process (see browser_shutdown::Shutdown()). |
+// |
+// Logoff/power off on Windows |
+// This happens when chrome recieves WM_ENDSESSION message. It |
+// notifies APP_EXITING, then close all tabs forcibly. This |
+// process does send APP_TERMINATING notification. This shutdown |
+// process cannot be blocked nor canceled. |
+// |
+// X IO Error on Linux and ChromeOS: |
+// When X server reports IO error, it's most likely X has gone away and |
+// chrome needs has to shutdown without make another call to X. |
+// This is similar to Window's logoff/power off process, except that |
+// chrome doesn't try to close browsers nor tabs. APP_TERMINATING is sent |
+// after APP_EXITING. |
+// |
+// ChromeOS specific: |
+// Fast shutdown |
+// When a user requested to quit browser either by wrench menu or |
+// ctrl-alt-q, and we know that shutdown will not be canceled (that is, |
+// all contents have no beforeunload handlers and there is no |
+// downloads in progress), chrome quits using fast shutdown process. |
+// It notifies APP_EXITING, followed by APP_TERMINATING, then |
+// tells SessionManager to start shutdown process. SessionManager sends |
+// SIGTERM back to chrome, which closes all browsers. |
+// |
+// Slow shutdown |
+// If there is a tab with beforeunload handlers, or a download is |
+// in progress, it will follow normal shutdown process. That is, |
+// it notifies APP_EXITING, tries to closes all browsers. APP_TERMINATING |
+// will be sent when the last browser is closd. Shutdown may be cancelled |
+// either by beforeunload handler or download dialog. |
+// |
+// Restart |
+// ChromeOS does not support restarting. It follows regular shutdown process, |
+// |
+// Power off |
+// A user pressed power button, or closed a lid on login screen. This is |
+// similar to Windows log-off/power-off scenario. Chrome receives SIGTERM |
+// and start shutdown process. It will close all tabs forcibly and shutdown |
+// cannot be canceled. |
+// |
+// Signout from Screen locker. |
+// A user clicked signout button on screen locker. This is basically same |
+// as Power off. Chrome asks session manager to stop session and session |
+// manager sends SIGTERM to chrome. |
+// |
+// Switching to Guest mode |
+// When a user selected guest mode, Chrome first writes exit_cleanly bit |
+// off to the disk (see g_browser_process->EndSession() in |
+// chromeos/login_utils.cc), then tells SessionManager to switch to guest |
+// mode. Session manager kills and restarts Chrome with guest mode flag. |
+// This process never use method in BrowserList, nor sends APP_EXITING |
+// or APP_TERMINATING (to restart fast). |
+// |
+// Note that different shutdown path |
+// |
+// Mac: |
+// T.B.D. |
+// |
+ |
// This object is instantiated when the first Browser object is added to the |
// list and delete when the last one is removed. It watches for loads and |
// creates histograms of some global object counts. |
@@ -201,15 +290,29 @@ bool AreAllBrowsersCloseable() { |
return true; |
} |
+// Sends out NOTIFICATION_APP_TERMINATING notification. |
+// Returns true if the notification is set, or false if the notification |
+// has already sent out before. |
+bool NotifyAppTerminating() { |
+ static bool notified = false; |
+ if (notified) |
+ return false; |
+ notified = true; |
+ NotificationService::current()->Notify( |
+ content::NOTIFICATION_APP_TERMINATING, |
+ NotificationService::AllSources(), |
+ NotificationService::NoDetails()); |
+ return true; |
+} |
+ |
#if defined(OS_CHROMEOS) |
-bool signout = false; |
+bool explicit_signout = false; |
// Fast shutdown for ChromeOS. It tells session manager to start |
// shutdown process when closing browser windows won't be canceled. |
// Returns true if fast shutdown is successfully started. |
bool FastShutdown() { |
- signout = true; |
if (chromeos::CrosLibrary::Get()->EnsureLoaded() |
&& AreAllBrowsersCloseable()) { |
BrowserList::NotifyAndTerminate(true); |
@@ -287,15 +390,12 @@ void BrowserList::AttemptExitInternal() { |
// static |
void BrowserList::NotifyAndTerminate(bool fast_path) { |
#if defined(OS_CHROMEOS) |
- if (!signout) |
+ if (browser_shutdown::ShutdownType() != browser_shutdown::BROWSER_EXIT); |
return; |
#endif |
if (fast_path) { |
- NotificationService::current()->Notify( |
- content::NOTIFICATION_APP_TERMINATING, |
- NotificationService::AllSources(), |
- NotificationService::NoDetails()); |
+ NotifyAppTerminating(); |
} |
#if defined(OS_CHROMEOS) |
@@ -357,10 +457,9 @@ void BrowserList::RemoveBrowser(Browser* browser) { |
// to call ProfileManager::ShutdownSessionServices() as part of the |
// shutdown, because Browser::WindowClosing() already makes sure that the |
// SessionService is created and notified. |
- NotificationService::current()->Notify( |
- content::NOTIFICATION_APP_TERMINATING, |
- NotificationService::AllSources(), |
- NotificationService::NoDetails()); |
+ // On ChromeOS, APP_TERMINATING might have already been sent when |
+ // shutdown is first requested. The call will be ignored in that case. |
+ NotifyAppTerminating(); |
AllBrowsersClosedAndAppExiting(); |
} |
} |
@@ -377,6 +476,9 @@ void BrowserList::RemoveObserver(BrowserList::Observer* observer) { |
// static |
void BrowserList::CloseAllBrowsers() { |
+ browser_shutdown::ShutdownType shutdown_type = |
+ browser_shutdown::GetShutdownType() |
+ /* |
bool session_ending = |
browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION; |
bool force_exit = false; |
@@ -384,6 +486,7 @@ void BrowserList::CloseAllBrowsers() { |
if (session_ending) |
force_exit = true; |
#endif |
+ */ |
// Tell everyone that we are shutting down. |
browser_shutdown::SetTryingToQuit(true); |
@@ -391,21 +494,29 @@ void BrowserList::CloseAllBrowsers() { |
// exit can restore all browsers open before exiting. |
ProfileManager::ShutdownSessionServices(); |
+ // If we're not closing browser, send APP_TERMINATING |
+ if (shutdown_type == browser_shutdown::SHUTDOWN_WITHOUT_CLOSE) { |
+ NotifyAppTerminating(); |
+ return; |
+ } |
+ |
// If there are no browsers, send the APP_TERMINATING action here. Otherwise, |
// it will be sent by RemoveBrowser() when the last browser has closed. |
if (force_exit || browsers_.empty()) { |
NotifyAndTerminate(true); |
return; |
} |
+ |
#if defined(OS_CHROMEOS) |
chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker( |
"StartedClosingWindows", false); |
#endif |
+ |
for (BrowserList::const_iterator i = BrowserList::begin(); |
i != BrowserList::end();) { |
Browser* browser = *i; |
achuithb
2011/10/28 22:22:26
Do you think you could also clean this loop up if
|
browser->window()->Close(); |
- if (!session_ending) { |
+ if (shutdown_type != browser_shutdown::POWER_OFF) { |
++i; |
} else { |
// This path is hit during logoff/power-down. In this case we won't get |
@@ -447,6 +558,7 @@ void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) { |
// static |
void BrowserList::AttemptUserExit() { |
+ browser_shutdown::OnShutdownStarting(browser_shutdown::BROWSER_EXIT); |
#if defined(OS_CHROMEOS) |
chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutStarted", false); |
// Write /tmp/uptime-logout-started as well. |
@@ -464,6 +576,7 @@ void BrowserList::AttemptUserExit() { |
state->SavePersistentPrefs(); |
} |
} |
+ |
if (FastShutdown()) |
return; |
#else |
@@ -481,6 +594,7 @@ void BrowserList::AttemptRestart() { |
// For CrOS instead of browser restart (which is not supported) perform a full |
// sign out. Session will be only restored if user has that setting set. |
// Same session restore behavior happens in case of full restart after update. |
+ // TODO(oshima): Should we use LoginLibrary::RestartJob()? |
AttemptUserExit(); |
#else |
// Set the flag to restore state after the restart. |
@@ -506,11 +620,13 @@ void BrowserList::AttemptExit() { |
void BrowserList::ExitCleanly() { |
// We always mark exit cleanly. |
g_browser_process->EndSession(); |
+ if (AreAllBrowsersCloseable()) |
+ |
AttemptExitInternal(); |
} |
#endif |
-static void TimeLimitedSessionEnding() { |
+static void TimeLimitedForceShutdown(browser_shutdown::ShutdownType type) { |
// Start watching for hang during shutdown, and crash it if takes too long. |
// We disarm when |shutdown_watcher| object is destroyed, which is when we |
// exit this function. |
@@ -524,8 +640,8 @@ static void TimeLimitedSessionEnding() { |
if (already_ended || !NotificationService::current()) |
return; |
already_ended = true; |
- |
- browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION); |
+ |
+ browser_shutdown::OnShutdownStarting(type); |
NotificationService::current()->Notify( |
content::NOTIFICATION_APP_EXITING, |
@@ -549,8 +665,8 @@ static void TimeLimitedSessionEnding() { |
} |
// static |
-void BrowserList::SessionEnding() { |
- TimeLimitedSessionEnding(); |
+void BrowserList::ForceShutdown(SessionEndingReason raeson) { |
+ TimeLimitedForceShutdown(reason); |
#if defined(OS_WIN) |
// At this point the message loop is still running yet we've shut everything |