Index: chrome/browser/ui/browser_list.cc |
=================================================================== |
--- chrome/browser/ui/browser_list.cc (revision 137868) |
+++ chrome/browser/ui/browser_list.cc (working copy) |
@@ -6,17 +6,14 @@ |
#include "base/command_line.h" |
#include "base/logging.h" |
-#include "base/message_loop.h" |
#include "base/metrics/histogram.h" |
#include "build/build_config.h" |
#include "chrome/browser/browser_process.h" |
#include "chrome/browser/browser_shutdown.h" |
-#include "chrome/browser/download/download_service.h" |
-#include "chrome/browser/metrics/thread_watcher.h" |
+#include "chrome/browser/lifetime/application_lifetime.h" |
#include "chrome/browser/prefs/pref_service.h" |
#include "chrome/browser/printing/background_printing_manager.h" |
#include "chrome/browser/profiles/profile.h" |
-#include "chrome/browser/profiles/profile_manager.h" |
#include "chrome/browser/ui/browser.h" |
#include "chrome/browser/ui/browser_window.h" |
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
@@ -31,17 +28,8 @@ |
#include "content/public/browser/render_process_host.h" |
#include "content/public/common/result_codes.h" |
-#if defined(OS_MACOSX) |
-#include "chrome/browser/chrome_browser_application_mac.h" |
-#endif |
- |
#if defined(OS_CHROMEOS) |
-#include "base/chromeos/chromeos_version.h" |
-#include "chrome/browser/chromeos/boot_times_loader.h" |
#include "chrome/browser/chromeos/login/user_manager.h" |
-#include "chromeos/dbus/dbus_thread_manager.h" |
-#include "chromeos/dbus/session_manager_client.h" |
-#include "chromeos/dbus/update_engine_client.h" |
#endif |
using content::WebContents; |
@@ -56,6 +44,8 @@ |
BrowserActivityObserver() { |
registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
content::NotificationService::AllSources()); |
+ registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING, |
+ content::NotificationService::AllSources()); |
} |
~BrowserActivityObserver() {} |
@@ -64,14 +54,17 @@ |
virtual void Observe(int type, |
const content::NotificationSource& source, |
const content::NotificationDetails& details) { |
- DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED); |
- const content::LoadCommittedDetails& load = |
- *content::Details<content::LoadCommittedDetails>(details).ptr(); |
- if (!load.is_navigation_to_different_page()) |
- return; // Don't log for subframes or other trivial types. |
+ if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { |
+ const content::LoadCommittedDetails& load = |
+ *content::Details<content::LoadCommittedDetails>(details).ptr(); |
+ if (!load.is_navigation_to_different_page()) |
+ return; // Don't log for subframes or other trivial types. |
- LogRenderProcessHostCount(); |
- LogBrowserTabCount(); |
+ LogRenderProcessHostCount(); |
+ LogBrowserTabCount(); |
+ } else if (type == content::NOTIFICATION_APP_TERMINATING) { |
+ delete this; |
+ } |
} |
// Counts the number of active RenderProcessHosts and logs them. |
@@ -136,44 +129,6 @@ |
return g_browser_process->background_printing_manager(); |
} |
-// Returns true if all browsers can be closed without user interaction. |
-// This currently checks if there is pending download, or if it needs to |
-// handle unload handler. |
-bool AreAllBrowsersCloseable() { |
- BrowserList::const_iterator browser_it = BrowserList::begin(); |
- if (browser_it == BrowserList::end()) |
- return true; |
- |
- // If there are any downloads active, all browsers are not closeable. |
- if (DownloadService::DownloadCountAllProfiles() > 0) |
- return false; |
- |
- // Check TabsNeedBeforeUnloadFired(). |
- for (; browser_it != BrowserList::end(); ++browser_it) { |
- if ((*browser_it)->TabsNeedBeforeUnloadFired()) |
- return false; |
- } |
- return true; |
-} |
- |
-// Emits APP_TERMINATING notification. It is guaranteed that the |
-// notification is sent only once. |
-void NotifyAppTerminating() { |
- static bool notified = false; |
- if (notified) |
- return; |
- notified = true; |
- content::NotificationService::current()->Notify( |
- content::NOTIFICATION_APP_TERMINATING, |
- content::NotificationService::AllSources(), |
- content::NotificationService::NoDetails()); |
-} |
- |
-#if defined(OS_CHROMEOS) |
-// Whether a session manager requested to shutdown. |
-bool g_session_manager_requested_shutdown = true; |
-#endif |
- |
} // namespace |
// static |
@@ -200,78 +155,6 @@ |
} |
// static |
-void BrowserList::MarkAsCleanShutdown() { |
- for (const_iterator i = begin(); i != end(); ++i) { |
- (*i)->profile()->MarkAsCleanShutdown(); |
- } |
-} |
- |
-void BrowserList::AttemptExitInternal() { |
- content::NotificationService::current()->Notify( |
- content::NOTIFICATION_APP_EXITING, |
- content::NotificationService::AllSources(), |
- content::NotificationService::NoDetails()); |
- |
-#if !defined(OS_MACOSX) |
- // On most platforms, closing all windows causes the application to exit. |
- CloseAllBrowsers(); |
-#else |
- // On the Mac, the application continues to run once all windows are closed. |
- // Terminate will result in a CloseAllBrowsers() call, and once (and if) |
- // that is done, will cause the application to exit cleanly. |
- chrome_browser_application_mac::Terminate(); |
-#endif |
-} |
- |
-// static |
-void BrowserList::NotifyAndTerminate(bool fast_path) { |
-#if defined(OS_CHROMEOS) |
- static bool notified = false; |
- // Don't ask SessionManager to shutdown if |
- // a) a shutdown request has already been sent. |
- // b) shutdown request comes from session manager. |
- if (notified || g_session_manager_requested_shutdown) |
- return; |
- notified = true; |
-#endif |
- |
- if (fast_path) |
- NotifyAppTerminating(); |
- |
-#if defined(OS_CHROMEOS) |
- if (base::chromeos::IsRunningOnChromeOS()) { |
- // If we're on a ChromeOS device, reboot if an update has been applied, |
- // or else signal the session manager to log out. |
- chromeos::UpdateEngineClient* update_engine_client |
- = chromeos::DBusThreadManager::Get()->GetUpdateEngineClient(); |
- if (update_engine_client->GetLastStatus().status == |
- chromeos::UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) { |
- update_engine_client->RebootAfterUpdate(); |
- } else { |
- chromeos::DBusThreadManager::Get()->GetSessionManagerClient() |
- ->StopSession(); |
- } |
- } else { |
- // If running the Chrome OS build, but we're not on the device, act |
- // as if we received signal from SessionManager. |
- content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
- base::Bind(&BrowserList::ExitCleanly)); |
- } |
-#endif |
-} |
- |
-void BrowserList::OnAppExiting() { |
- static bool notified = false; |
- if (notified) |
- return; |
- notified = true; |
- |
- delete activity_observer; |
- activity_observer = NULL; |
- HandleAppExitingForPlatform(); |
-} |
- |
-// static |
void BrowserList::RemoveBrowser(Browser* browser) { |
RemoveBrowserFrom(browser, &last_active_browsers()); |
@@ -319,8 +202,8 @@ |
// to call ProfileManager::ShutdownSessionServices() as part of the |
// shutdown, because Browser::WindowClosing() already makes sure that the |
// SessionService is created and notified. |
- NotifyAppTerminating(); |
- OnAppExiting(); |
+ browser::NotifyAppTerminating(); |
+ browser::OnAppExiting(); |
} |
} |
@@ -334,58 +217,6 @@ |
observers().RemoveObserver(observer); |
} |
-// static |
-void BrowserList::CloseAllBrowsers() { |
- bool session_ending = |
- browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION; |
- // Tell everyone that we are shutting down. |
- browser_shutdown::SetTryingToQuit(true); |
- |
- // Before we close the browsers shutdown all session services. That way an |
- // exit can restore all browsers open before exiting. |
- ProfileManager::ShutdownSessionServices(); |
- |
- // 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 (browser_shutdown::ShuttingDownWithoutClosingBrowsers() || |
- browsers().empty()) { |
- NotifyAndTerminate(true); |
- OnAppExiting(); |
- 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; |
- browser->window()->Close(); |
- if (!session_ending) { |
- ++i; |
- } else { |
- // This path is hit during logoff/power-down. In this case we won't get |
- // a final message and so we force the browser to be deleted. |
- // Close doesn't immediately destroy the browser |
- // (Browser::TabStripEmpty() uses invoke later) but when we're ending the |
- // session we need to make sure the browser is destroyed now. So, invoke |
- // DestroyBrowser to make sure the browser is deleted and cleanup can |
- // happen. |
- while (browser->tab_count()) |
- delete browser->GetTabContentsWrapperAt(0); |
- browser->window()->DestroyBrowser(); |
- i = BrowserList::begin(); |
- if (i != BrowserList::end() && browser == *i) { |
- // Destroying the browser should have removed it from the browser list. |
- // We should never get here. |
- NOTREACHED(); |
- return; |
- } |
- } |
- } |
-} |
- |
void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) { |
BrowserVector browsers_to_close; |
for (BrowserList::const_iterator i = BrowserList::begin(); |
@@ -401,172 +232,6 @@ |
} |
// static |
-void BrowserList::AttemptUserExit() { |
-#if defined(OS_CHROMEOS) |
- chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutStarted", false); |
- // Write /tmp/uptime-logout-started as well. |
- const char kLogoutStarted[] = "logout-started"; |
- chromeos::BootTimesLoader::Get()->RecordCurrentStats(kLogoutStarted); |
- |
- // Login screen should show up in owner's locale. |
- PrefService* state = g_browser_process->local_state(); |
- if (state) { |
- std::string owner_locale = state->GetString(prefs::kOwnerLocale); |
- if (!owner_locale.empty() && |
- state->GetString(prefs::kApplicationLocale) != owner_locale && |
- !state->IsManagedPreference(prefs::kApplicationLocale)) { |
- state->SetString(prefs::kApplicationLocale, owner_locale); |
- state->CommitPendingWrite(); |
- } |
- } |
- g_session_manager_requested_shutdown = false; |
- // On ChromeOS, always terminate the browser, regardless of the result of |
- // AreAllBrowsersCloseable(). See crbug.com/123107. |
- BrowserList::NotifyAndTerminate(true); |
-#else |
- // Reset the restart bit that might have been set in cancelled restart |
- // request. |
- PrefService* pref_service = g_browser_process->local_state(); |
- pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, false); |
- AttemptExitInternal(); |
-#endif |
-} |
- |
-// static |
-void BrowserList::AttemptRestart() { |
- if (!CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kDisableRestoreSessionState)) { |
- BrowserVector::const_iterator it; |
- for (it = begin(); it != end(); ++it) |
- content::BrowserContext::SaveSessionState((*it)->profile()); |
- } |
- |
- PrefService* pref_service = g_browser_process->local_state(); |
- pref_service->SetBoolean(prefs::kWasRestarted, true); |
- |
-#if defined(OS_CHROMEOS) |
- // 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. |
- AttemptUserExit(); |
-#else |
- // Set the flag to restore state after the restart. |
- pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true); |
- AttemptExit(); |
-#endif |
-} |
- |
-// static |
-void BrowserList::AttemptExit() { |
- // If we know that all browsers can be closed without blocking, |
- // don't notify users of crashes beyond this point. |
- // Note that MarkAsCleanShutdown does not set UMA's exit cleanly bit |
- // so crashes during shutdown are still reported in UMA. |
- if (AreAllBrowsersCloseable()) |
- MarkAsCleanShutdown(); |
- AttemptExitInternal(); |
-} |
- |
-#if defined(OS_CHROMEOS) |
-// A function called when SIGTERM is received. |
-// static |
-void BrowserList::ExitCleanly() { |
- // We always mark exit cleanly because SessionManager may kill |
- // chrome in 3 seconds after SIGTERM. |
- g_browser_process->EndSession(); |
- |
- // Don't block when SIGTERM is received. AreaAllBrowsersCloseable() |
- // can be false in following cases. a) power-off b) signout from |
- // screen locker. |
- if (!AreAllBrowsersCloseable()) |
- browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION); |
- AttemptExitInternal(); |
-} |
-#endif |
- |
-// static |
-void BrowserList::SessionEnding() { |
- // This is a time-limited shutdown where we need to write as much to |
- // disk as we can as soon as we can, and where we must kill the |
- // process within a hang timeout to avoid user prompts. |
- |
- // 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. |
- ShutdownWatcherHelper shutdown_watcher; |
- shutdown_watcher.Arm(base::TimeDelta::FromSeconds(90)); |
- |
- // EndSession is invoked once per frame. Only do something the first time. |
- static bool already_ended = false; |
- // We may get called in the middle of shutdown, e.g. http://crbug.com/70852 |
- // In this case, do nothing. |
- if (already_ended || !content::NotificationService::current()) |
- return; |
- already_ended = true; |
- |
- browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION); |
- |
- content::NotificationService::current()->Notify( |
- content::NOTIFICATION_APP_EXITING, |
- content::NotificationService::AllSources(), |
- content::NotificationService::NoDetails()); |
- |
- // Write important data first. |
- g_browser_process->EndSession(); |
- |
- BrowserList::CloseAllBrowsers(); |
- |
- // Send out notification. This is used during testing so that the test harness |
- // can properly shutdown before we exit. |
- content::NotificationService::current()->Notify( |
- chrome::NOTIFICATION_SESSION_END, |
- content::NotificationService::AllSources(), |
- content::NotificationService::NoDetails()); |
- |
- // This will end by terminating the process. |
- content::ImmediateShutdownAndExitProcess(); |
-} |
- |
-// static |
-int BrowserList::keep_alive_count_ = 0; |
- |
-// static |
-void BrowserList::StartKeepAlive() { |
- // Increment the browser process refcount as long as we're keeping the |
- // application alive. |
- if (!WillKeepAlive()) |
- g_browser_process->AddRefModule(); |
- keep_alive_count_++; |
-} |
- |
-// static |
-void BrowserList::EndKeepAlive() { |
- DCHECK_GT(keep_alive_count_, 0); |
- keep_alive_count_--; |
- |
- DCHECK(g_browser_process); |
- // Although we should have a browser process, if there is none, |
- // there is nothing to do. |
- if (!g_browser_process) return; |
- |
- // Allow the app to shutdown again. |
- if (!WillKeepAlive()) { |
- g_browser_process->ReleaseModule(); |
- // If there are no browsers open and we aren't already shutting down, |
- // initiate a shutdown. Also skips shutdown if this is a unit test |
- // (MessageLoop::current() == null). |
- if (browsers().empty() && !browser_shutdown::IsTryingToQuit() && |
- MessageLoop::current()) |
- CloseAllBrowsers(); |
- } |
-} |
- |
-// static |
-bool BrowserList::WillKeepAlive() { |
- return keep_alive_count_ > 0; |
-} |
- |
-// static |
BrowserList::const_iterator BrowserList::begin() { |
return browsers().begin(); |
} |