Index: chrome/browser/lifetime/application_lifetime.cc |
=================================================================== |
--- chrome/browser/lifetime/application_lifetime.cc (revision 0) |
+++ chrome/browser/lifetime/application_lifetime.cc (working copy) |
@@ -7,14 +7,12 @@ |
#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/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" |
@@ -26,10 +24,7 @@ |
#include "content/public/browser/browser_shutdown.h" |
#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/navigation_details.h" |
-#include "content/public/browser/notification_registrar.h" |
#include "content/public/browser/notification_service.h" |
-#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" |
@@ -44,98 +39,9 @@ |
#include "chromeos/dbus/update_engine_client.h" |
#endif |
-using content::WebContents; |
- |
+namespace browser { |
namespace { |
-// 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. |
-class BrowserActivityObserver : public content::NotificationObserver { |
- public: |
- BrowserActivityObserver() { |
- registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
- content::NotificationService::AllSources()); |
- } |
- ~BrowserActivityObserver() {} |
- |
- private: |
- // content::NotificationObserver implementation. |
- 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. |
- |
- LogRenderProcessHostCount(); |
- LogBrowserTabCount(); |
- } |
- |
- // Counts the number of active RenderProcessHosts and logs them. |
- void LogRenderProcessHostCount() const { |
- int hosts_count = 0; |
- for (content::RenderProcessHost::iterator i( |
- content::RenderProcessHost::AllHostsIterator()); |
- !i.IsAtEnd(); i.Advance()) |
- ++hosts_count; |
- UMA_HISTOGRAM_CUSTOM_COUNTS("MPArch.RPHCountPerLoad", hosts_count, |
- 1, 50, 50); |
- } |
- |
- // Counts the number of tabs in each browser window and logs them. This is |
- // different than the number of WebContents objects since WebContents objects |
- // can be used for popups and in dialog boxes. We're just counting toplevel |
- // tabs here. |
- void LogBrowserTabCount() const { |
- int tab_count = 0; |
- for (BrowserList::const_iterator browser_iterator = BrowserList::begin(); |
- browser_iterator != BrowserList::end(); browser_iterator++) { |
- // Record how many tabs each window has open. |
- UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerWindow", |
- (*browser_iterator)->tab_count(), 1, 200, 50); |
- tab_count += (*browser_iterator)->tab_count(); |
- } |
- // Record how many tabs total are open (across all windows). |
- UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerLoad", tab_count, 1, 200, 50); |
- |
- Browser* browser = BrowserList::GetLastActive(); |
- if (browser) { |
- // Record how many tabs the active window has open. |
- UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountActiveWindow", |
- browser->tab_count(), 1, 200, 50); |
- } |
- } |
- |
- content::NotificationRegistrar registrar_; |
- |
- DISALLOW_COPY_AND_ASSIGN(BrowserActivityObserver); |
-}; |
- |
-BrowserActivityObserver* activity_observer = NULL; |
- |
-static BrowserList::BrowserVector& browsers() { |
- CR_DEFINE_STATIC_LOCAL(BrowserList::BrowserVector, browser_vector, ()); |
- return browser_vector; |
-} |
- |
-static BrowserList::BrowserVector& last_active_browsers() { |
- CR_DEFINE_STATIC_LOCAL(BrowserList::BrowserVector, last_active_vector, ()); |
- return last_active_vector; |
-} |
- |
-static ObserverList<BrowserList::Observer>& observers() { |
- CR_DEFINE_STATIC_LOCAL( |
- ObserverList<BrowserList::Observer>, observer_vector, ()); |
- return observer_vector; |
-} |
- |
-printing::BackgroundPrintingManager* GetBackgroundPrintingManager() { |
- 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. |
@@ -156,18 +62,7 @@ |
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()); |
-} |
+int g_keep_alive_count = 0; |
#if defined(OS_CHROMEOS) |
// Whether a session manager requested to shutdown. |
@@ -176,37 +71,15 @@ |
} // namespace |
-// static |
-void BrowserList::AddBrowser(Browser* browser) { |
- DCHECK(browser); |
- browsers().push_back(browser); |
- |
- g_browser_process->AddRefModule(); |
- |
- if (!activity_observer) |
- activity_observer = new BrowserActivityObserver; |
- |
- content::NotificationService::current()->Notify( |
- chrome::NOTIFICATION_BROWSER_OPENED, |
- content::Source<Browser>(browser), |
- content::NotificationService::NoDetails()); |
- |
- // Send out notifications after add has occurred. Do some basic checking to |
- // try to catch evil observers that change the list from under us. |
- size_t original_count = observers().size(); |
- FOR_EACH_OBSERVER(Observer, observers(), OnBrowserAdded(browser)); |
- DCHECK_EQ(original_count, observers().size()) |
- << "observer list modified during notification"; |
-} |
- |
-// static |
-void BrowserList::MarkAsCleanShutdown() { |
- for (const_iterator i = begin(); i != end(); ++i) { |
+void MarkAsCleanShutdown() { |
+ // TODO(beng): Can this use ProfileManager::GetLoadedProfiles() instead? |
+ for (BrowserList::const_iterator i = BrowserList::begin(); |
+ i != BrowserList::end(); ++i) { |
(*i)->profile()->MarkAsCleanShutdown(); |
} |
} |
-void BrowserList::AttemptExitInternal() { |
+void AttemptExitInternal() { |
content::NotificationService::current()->Notify( |
content::NOTIFICATION_APP_EXITING, |
content::NotificationService::AllSources(), |
@@ -223,8 +96,18 @@ |
#endif |
} |
-// static |
-void BrowserList::NotifyAndTerminate(bool fast_path) { |
+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()); |
+} |
+ |
+void NotifyAndTerminate(bool fast_path) { |
#if defined(OS_CHROMEOS) |
static bool notified = false; |
// Don't ask SessionManager to shutdown if |
@@ -255,87 +138,20 @@ |
// 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)); |
+ base::Bind(&browser::ExitCleanly)); |
} |
#endif |
} |
-void BrowserList::OnAppExiting() { |
+void 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()); |
- |
- // Many UI tests rely on closing the last browser window quitting the |
- // application. |
- // Mac: Closing all windows does not indicate quitting the application. Lie |
- // for now and ignore behavior outside of unit tests. |
- // ChromeOS: Force closing last window to close app with flag. |
- // TODO(andybons | pkotwicz): Fix the UI tests to Do The Right Thing. |
-#if defined(OS_CHROMEOS) |
- bool closing_app; |
- if (CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kDisableZeroBrowsersOpenForTests)) |
- closing_app = (browsers().size() == 1); |
- else |
- closing_app = (browsers().size() == 1 && |
- browser_shutdown::IsTryingToQuit()); |
-#else |
- bool closing_app = (browsers().size() == 1); |
-#endif // OS_CHROMEOS |
- |
- content::NotificationService::current()->Notify( |
- chrome::NOTIFICATION_BROWSER_CLOSED, |
- content::Source<Browser>(browser), |
- content::Details<bool>(&closing_app)); |
- |
- RemoveBrowserFrom(browser, &browsers()); |
- |
- // Do some basic checking to try to catch evil observers |
- // that change the list from under us. |
- size_t original_count = observers().size(); |
- FOR_EACH_OBSERVER(Observer, observers(), OnBrowserRemoved(browser)); |
- DCHECK_EQ(original_count, observers().size()) |
- << "observer list modified during notification"; |
- |
- g_browser_process->ReleaseModule(); |
- |
- // If we're exiting, send out the APP_TERMINATING notification to allow other |
- // modules to shut themselves down. |
- if (browsers().empty() && |
- (browser_shutdown::IsTryingToQuit() || |
- g_browser_process->IsShuttingDown())) { |
- // Last browser has just closed, and this is a user-initiated quit or there |
- // is no module keeping the app alive, so send out our notification. No need |
- // to call ProfileManager::ShutdownSessionServices() as part of the |
- // shutdown, because Browser::WindowClosing() already makes sure that the |
- // SessionService is created and notified. |
- NotifyAppTerminating(); |
- OnAppExiting(); |
- } |
-} |
- |
-// static |
-void BrowserList::AddObserver(BrowserList::Observer* observer) { |
- observers().AddObserver(observer); |
-} |
- |
-// static |
-void BrowserList::RemoveObserver(BrowserList::Observer* observer) { |
- observers().RemoveObserver(observer); |
-} |
- |
-// static |
-void BrowserList::CloseAllBrowsers() { |
+void CloseAllBrowsers() { |
bool session_ending = |
browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION; |
// Tell everyone that we are shutting down. |
@@ -348,7 +164,7 @@ |
// 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()) { |
+ BrowserList::empty()) { |
NotifyAndTerminate(true); |
OnAppExiting(); |
return; |
@@ -386,22 +202,7 @@ |
} |
} |
-void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) { |
- BrowserVector browsers_to_close; |
- for (BrowserList::const_iterator i = BrowserList::begin(); |
- i != BrowserList::end(); ++i) { |
- if ((*i)->profile()->GetOriginalProfile() == profile->GetOriginalProfile()) |
- browsers_to_close.push_back(*i); |
- } |
- |
- for (BrowserVector::const_iterator i = browsers_to_close.begin(); |
- i != browsers_to_close.end(); ++i) { |
- (*i)->window()->Close(); |
- } |
-} |
- |
-// static |
-void BrowserList::AttemptUserExit() { |
+void AttemptUserExit() { |
#if defined(OS_CHROMEOS) |
chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutStarted", false); |
// Write /tmp/uptime-logout-started as well. |
@@ -422,7 +223,7 @@ |
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); |
+ NotifyAndTerminate(true); |
#else |
// Reset the restart bit that might have been set in cancelled restart |
// request. |
@@ -432,12 +233,12 @@ |
#endif |
} |
-// static |
-void BrowserList::AttemptRestart() { |
+void AttemptRestart() { |
if (!CommandLine::ForCurrentProcess()->HasSwitch( |
switches::kDisableRestoreSessionState)) { |
- BrowserVector::const_iterator it; |
- for (it = begin(); it != end(); ++it) |
+ // TODO(beng): Can this use ProfileManager::GetLoadedProfiles instead? |
+ BrowserList::const_iterator it; |
+ for (it = BrowserList::begin(); it != BrowserList::end(); ++it) |
content::BrowserContext::SaveSessionState((*it)->profile()); |
} |
@@ -456,8 +257,7 @@ |
#endif |
} |
-// static |
-void BrowserList::AttemptExit() { |
+void 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 |
@@ -469,8 +269,7 @@ |
#if defined(OS_CHROMEOS) |
// A function called when SIGTERM is received. |
-// static |
-void BrowserList::ExitCleanly() { |
+void ExitCleanly() { |
// We always mark exit cleanly because SessionManager may kill |
// chrome in 3 seconds after SIGTERM. |
g_browser_process->EndSession(); |
@@ -484,8 +283,7 @@ |
} |
#endif |
-// static |
-void BrowserList::SessionEnding() { |
+void 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. |
@@ -514,7 +312,7 @@ |
// Write important data first. |
g_browser_process->EndSession(); |
- BrowserList::CloseAllBrowsers(); |
+ CloseAllBrowsers(); |
// Send out notification. This is used during testing so that the test harness |
// can properly shutdown before we exit. |
@@ -527,22 +325,17 @@ |
content::ImmediateShutdownAndExitProcess(); |
} |
-// static |
-int BrowserList::keep_alive_count_ = 0; |
- |
-// static |
-void BrowserList::StartKeepAlive() { |
+void StartKeepAlive() { |
// Increment the browser process refcount as long as we're keeping the |
// application alive. |
if (!WillKeepAlive()) |
g_browser_process->AddRefModule(); |
- keep_alive_count_++; |
+ ++g_keep_alive_count; |
} |
-// static |
-void BrowserList::EndKeepAlive() { |
- DCHECK_GT(keep_alive_count_, 0); |
- keep_alive_count_--; |
+void EndKeepAlive() { |
+ DCHECK_GT(g_keep_alive_count, 0); |
+ --g_keep_alive_count; |
DCHECK(g_browser_process); |
// Although we should have a browser process, if there is none, |
@@ -555,142 +348,14 @@ |
// 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() && |
+ if (BrowserList::empty() && !browser_shutdown::IsTryingToQuit() && |
MessageLoop::current()) |
CloseAllBrowsers(); |
} |
} |
-// static |
-bool BrowserList::WillKeepAlive() { |
- return keep_alive_count_ > 0; |
+bool WillKeepAlive() { |
+ return g_keep_alive_count > 0; |
} |
-// static |
-BrowserList::const_iterator BrowserList::begin() { |
- return browsers().begin(); |
-} |
- |
-// static |
-BrowserList::const_iterator BrowserList::end() { |
- return browsers().end(); |
-} |
- |
-// static |
-bool BrowserList::empty() { |
- return browsers().empty(); |
-} |
- |
-// static |
-size_t BrowserList::size() { |
- return browsers().size(); |
-} |
- |
-// static |
-void BrowserList::SetLastActive(Browser* browser) { |
- // If the browser is currently trying to quit, we don't want to set the last |
- // active browser because that can alter the last active browser that the user |
- // intended depending on the order in which the windows close. |
- if (browser_shutdown::IsTryingToQuit()) |
- return; |
- RemoveBrowserFrom(browser, &last_active_browsers()); |
- last_active_browsers().push_back(browser); |
- |
- FOR_EACH_OBSERVER(Observer, observers(), OnBrowserSetLastActive(browser)); |
-} |
- |
-// static |
-Browser* BrowserList::GetLastActive() { |
- if (!last_active_browsers().empty()) |
- return *(last_active_browsers().rbegin()); |
- |
- return NULL; |
-} |
- |
-// static |
-BrowserList::const_reverse_iterator BrowserList::begin_last_active() { |
- return last_active_browsers().rbegin(); |
-} |
- |
-// static |
-BrowserList::const_reverse_iterator BrowserList::end_last_active() { |
- return last_active_browsers().rend(); |
-} |
- |
-// static |
-bool BrowserList::IsOffTheRecordSessionActive() { |
- for (BrowserList::const_iterator i = BrowserList::begin(); |
- i != BrowserList::end(); ++i) { |
- if ((*i)->profile()->IsOffTheRecord()) |
- return true; |
- } |
- return false; |
-} |
- |
-// static |
-bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile* profile) { |
-#if defined(OS_CHROMEOS) |
- // In ChromeOS, we assume that the default profile is always valid, so if |
- // we are in guest mode, keep the OTR profile active so it won't be deleted. |
- if (chromeos::UserManager::Get()->IsLoggedInAsGuest()) |
- return true; |
-#endif |
- for (BrowserList::const_iterator i = BrowserList::begin(); |
- i != BrowserList::end(); ++i) { |
- if ((*i)->profile()->IsSameProfile(profile) && |
- (*i)->profile()->IsOffTheRecord()) { |
- return true; |
- } |
- } |
- return false; |
-} |
- |
-// static |
-void BrowserList::RemoveBrowserFrom(Browser* browser, |
- BrowserVector* browser_list) { |
- const iterator remove_browser = |
- std::find(browser_list->begin(), browser_list->end(), browser); |
- if (remove_browser != browser_list->end()) |
- browser_list->erase(remove_browser); |
-} |
- |
-TabContentsIterator::TabContentsIterator() |
- : browser_iterator_(BrowserList::begin()), |
- web_view_index_(-1), |
- bg_printing_iterator_(GetBackgroundPrintingManager()->begin()), |
- cur_(NULL) { |
- Advance(); |
-} |
- |
-void TabContentsIterator::Advance() { |
- // The current WebContents should be valid unless we are at the beginning. |
- DCHECK(cur_ || (web_view_index_ == -1 && |
- browser_iterator_ == BrowserList::begin())) |
- << "Trying to advance past the end"; |
- |
- // Update cur_ to the next WebContents in the list. |
- while (browser_iterator_ != BrowserList::end()) { |
- if (++web_view_index_ >= (*browser_iterator_)->tab_count()) { |
- // Advance to the next Browser in the list. |
- ++browser_iterator_; |
- web_view_index_ = -1; |
- continue; |
- } |
- |
- TabContentsWrapper* next_tab = |
- (*browser_iterator_)->GetTabContentsWrapperAt(web_view_index_); |
- if (next_tab) { |
- cur_ = next_tab; |
- return; |
- } |
- } |
- // If no more WebContents from Browsers, check the BackgroundPrintingManager. |
- while (bg_printing_iterator_ != GetBackgroundPrintingManager()->end()) { |
- cur_ = *bg_printing_iterator_; |
- CHECK(cur_); |
- ++bg_printing_iterator_; |
- return; |
- } |
- // Reached the end - no more WebContents. |
- cur_ = NULL; |
-} |
+} // namespace browser |