| 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
|
|
|