13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// found in the LICENSE file.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/lifetime/browser_close_manager.h"
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/background/background_mode_manager.h"
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/browser_process.h"
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/browser_shutdown.h"
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/download/download_service.h"
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/download/download_service_factory.h"
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_iterator.h"
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/chrome_pages.h"
180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/web_contents.h"
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)BrowserCloseManager::BrowserCloseManager() : current_browser_(NULL) {}
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)BrowserCloseManager::~BrowserCloseManager() {}
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::StartClosingBrowsers() {
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // If the session is ending, skip straight to closing the browsers. There's no
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // time to wait for beforeunload dialogs.
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION) {
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Tell everyone that we are shutting down.
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    browser_shutdown::SetTryingToQuit(true);
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CloseBrowsers();
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  TryToCloseBrowsers();
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::CancelBrowserClose() {
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  browser_shutdown::SetTryingToQuit(false);
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    it->ResetBeforeUnloadHandlers();
423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::TryToCloseBrowsers() {
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If all browser windows can immediately be closed, fall out of this loop and
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // close the browsers. If any browser window cannot be closed, temporarily
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // stop closing. CallBeforeUnloadHandlers prompts the user and calls
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // OnBrowserReportCloseable with the result. If the user confirms the close,
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // this will trigger TryToCloseBrowsers to try again.
513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (it->CallBeforeUnloadHandlers(
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            base::Bind(&BrowserCloseManager::OnBrowserReportCloseable, this))) {
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      current_browser_ = *it;
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return;
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CheckForDownloadsInProgress();
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::OnBrowserReportCloseable(bool proceed) {
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!current_browser_)
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  current_browser_ = NULL;
663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (proceed)
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    TryToCloseBrowsers();
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  else
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CancelBrowserClose();
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::CheckForDownloadsInProgress() {
748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int download_count = DownloadService::NonMaliciousDownloadCountAllProfiles();
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (download_count == 0) {
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CloseBrowsers();
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ConfirmCloseWithPendingDownloads(
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      download_count,
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&BrowserCloseManager::OnReportDownloadsCancellable, this));
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::ConfirmCloseWithPendingDownloads(
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int download_count,
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::Callback<void(bool)>& callback) {
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Browser* browser =
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      BrowserList::GetInstance(chrome::GetActiveDesktop())->GetLastActive();
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(browser);
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  browser->window()->ConfirmBrowserCloseWithPendingDownloads(
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      download_count,
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN,
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      true,
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      callback);
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::OnReportDownloadsCancellable(bool proceed) {
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (proceed) {
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CloseBrowsers();
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CancelBrowserClose();
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Open the downloads page for each profile with downloads in progress.
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<Profile*> profiles(
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      g_browser_process->profile_manager()->GetLoadedProfiles());
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (std::vector<Profile*>::iterator it = profiles.begin();
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       it != profiles.end();
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       ++it) {
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DownloadService* download_service =
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        DownloadServiceFactory::GetForBrowserContext(*it);
1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (download_service->NonMaliciousDownloadCount() > 0) {
1140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::ScopedTabbedBrowserDisplayer displayer(
1150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          *it, chrome::GetActiveDesktop());
1160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::ShowDownloads(displayer.browser());
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::CloseBrowsers() {
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#if defined(ENABLE_SESSION_SERVICE)
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Before we close the browsers shutdown all session services. That way an
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // exit can restore all browsers open before exiting.
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ProfileManager::ShutdownSessionServices();
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#endif
1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!browser_shutdown::IsTryingToQuit()) {
1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    BackgroundModeManager* background_mode_manager =
1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        g_browser_process->background_mode_manager();
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (background_mode_manager)
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      background_mode_manager->SuspendBackgroundMode();
1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool session_ending =
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION;
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (scoped_ptr<chrome::BrowserIterator> it_ptr(
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           new chrome::BrowserIterator());
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       !it_ptr->done();) {
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    Browser* browser = **it_ptr;
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    browser->window()->Close();
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!session_ending) {
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      it_ptr->Next();
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    } else {
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // This path is hit during logoff/power-down. In this case we won't get
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // a final message and so we force the browser to be deleted.
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // Close doesn't immediately destroy the browser
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // (Browser::TabStripEmpty() uses invoke later) but when we're ending the
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // session we need to make sure the browser is destroyed now. So, invoke
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // DestroyBrowser to make sure the browser is deleted and cleanup can
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // happen.
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      while (browser->tab_strip_model()->count())
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        delete browser->tab_strip_model()->GetWebContentsAt(0);
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      browser->window()->DestroyBrowser();
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      it_ptr.reset(new chrome::BrowserIterator());
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (!it_ptr->done() && browser == **it_ptr) {
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // Destroying the browser should have removed it from the browser list.
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // We should never get here.
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        NOTREACHED();
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return;
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
164