1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/lifetime/browser_close_manager.h" 6 7 #include "chrome/browser/background/background_mode_manager.h" 8 #include "chrome/browser/browser_process.h" 9 #include "chrome/browser/browser_shutdown.h" 10 #include "chrome/browser/download/download_service.h" 11 #include "chrome/browser/download/download_service_factory.h" 12 #include "chrome/browser/profiles/profile_manager.h" 13 #include "chrome/browser/ui/browser.h" 14 #include "chrome/browser/ui/browser_iterator.h" 15 #include "chrome/browser/ui/browser_list.h" 16 #include "chrome/browser/ui/browser_window.h" 17 #include "chrome/browser/ui/chrome_pages.h" 18 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" 20 #include "content/public/browser/web_contents.h" 21 22 BrowserCloseManager::BrowserCloseManager() : current_browser_(NULL) {} 23 24 BrowserCloseManager::~BrowserCloseManager() {} 25 26 void BrowserCloseManager::StartClosingBrowsers() { 27 // If the session is ending, skip straight to closing the browsers. There's no 28 // time to wait for beforeunload dialogs. 29 if (browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION) { 30 // Tell everyone that we are shutting down. 31 browser_shutdown::SetTryingToQuit(true); 32 CloseBrowsers(); 33 return; 34 } 35 TryToCloseBrowsers(); 36 } 37 38 void BrowserCloseManager::CancelBrowserClose() { 39 browser_shutdown::SetTryingToQuit(false); 40 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 41 it->ResetBeforeUnloadHandlers(); 42 } 43 } 44 45 void BrowserCloseManager::TryToCloseBrowsers() { 46 // If all browser windows can immediately be closed, fall out of this loop and 47 // close the browsers. If any browser window cannot be closed, temporarily 48 // stop closing. CallBeforeUnloadHandlers prompts the user and calls 49 // OnBrowserReportCloseable with the result. If the user confirms the close, 50 // this will trigger TryToCloseBrowsers to try again. 51 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 52 if (it->CallBeforeUnloadHandlers( 53 base::Bind(&BrowserCloseManager::OnBrowserReportCloseable, this))) { 54 current_browser_ = *it; 55 return; 56 } 57 } 58 CheckForDownloadsInProgress(); 59 } 60 61 void BrowserCloseManager::OnBrowserReportCloseable(bool proceed) { 62 if (!current_browser_) 63 return; 64 65 current_browser_ = NULL; 66 67 if (proceed) 68 TryToCloseBrowsers(); 69 else 70 CancelBrowserClose(); 71 } 72 73 void BrowserCloseManager::CheckForDownloadsInProgress() { 74 int download_count = DownloadService::NonMaliciousDownloadCountAllProfiles(); 75 if (download_count == 0) { 76 CloseBrowsers(); 77 return; 78 } 79 ConfirmCloseWithPendingDownloads( 80 download_count, 81 base::Bind(&BrowserCloseManager::OnReportDownloadsCancellable, this)); 82 } 83 84 void BrowserCloseManager::ConfirmCloseWithPendingDownloads( 85 int download_count, 86 const base::Callback<void(bool)>& callback) { 87 Browser* browser = 88 BrowserList::GetInstance(chrome::GetActiveDesktop())->GetLastActive(); 89 DCHECK(browser); 90 browser->window()->ConfirmBrowserCloseWithPendingDownloads( 91 download_count, 92 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN, 93 true, 94 callback); 95 } 96 97 void BrowserCloseManager::OnReportDownloadsCancellable(bool proceed) { 98 if (proceed) { 99 CloseBrowsers(); 100 return; 101 } 102 103 CancelBrowserClose(); 104 105 // Open the downloads page for each profile with downloads in progress. 106 std::vector<Profile*> profiles( 107 g_browser_process->profile_manager()->GetLoadedProfiles()); 108 for (std::vector<Profile*>::iterator it = profiles.begin(); 109 it != profiles.end(); 110 ++it) { 111 DownloadService* download_service = 112 DownloadServiceFactory::GetForBrowserContext(*it); 113 if (download_service->NonMaliciousDownloadCount() > 0) { 114 chrome::ScopedTabbedBrowserDisplayer displayer( 115 *it, chrome::GetActiveDesktop()); 116 chrome::ShowDownloads(displayer.browser()); 117 } 118 } 119 } 120 121 void BrowserCloseManager::CloseBrowsers() { 122 #if defined(ENABLE_SESSION_SERVICE) 123 // Before we close the browsers shutdown all session services. That way an 124 // exit can restore all browsers open before exiting. 125 ProfileManager::ShutdownSessionServices(); 126 #endif 127 if (!browser_shutdown::IsTryingToQuit()) { 128 BackgroundModeManager* background_mode_manager = 129 g_browser_process->background_mode_manager(); 130 if (background_mode_manager) 131 background_mode_manager->SuspendBackgroundMode(); 132 } 133 134 bool session_ending = 135 browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION; 136 for (scoped_ptr<chrome::BrowserIterator> it_ptr( 137 new chrome::BrowserIterator()); 138 !it_ptr->done();) { 139 Browser* browser = **it_ptr; 140 browser->window()->Close(); 141 if (!session_ending) { 142 it_ptr->Next(); 143 } else { 144 // This path is hit during logoff/power-down. In this case we won't get 145 // a final message and so we force the browser to be deleted. 146 // Close doesn't immediately destroy the browser 147 // (Browser::TabStripEmpty() uses invoke later) but when we're ending the 148 // session we need to make sure the browser is destroyed now. So, invoke 149 // DestroyBrowser to make sure the browser is deleted and cleanup can 150 // happen. 151 while (browser->tab_strip_model()->count()) 152 delete browser->tab_strip_model()->GetWebContentsAt(0); 153 browser->window()->DestroyBrowser(); 154 it_ptr.reset(new chrome::BrowserIterator()); 155 if (!it_ptr->done() && browser == **it_ptr) { 156 // Destroying the browser should have removed it from the browser list. 157 // We should never get here. 158 NOTREACHED(); 159 return; 160 } 161 } 162 } 163 } 164