browser_close_manager.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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)
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/command_line.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_finder.h"
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_iterator.h"
163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/chrome_pages.h"
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/web_contents.h"
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)BrowserCloseManager::BrowserCloseManager() : current_browser_(NULL) {}
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)BrowserCloseManager::~BrowserCloseManager() {}
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::StartClosingBrowsers() {
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If the session is ending or batch browser shutdown is disabled, skip
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // straight to closing the browsers. In the former case, there's no time to
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // wait for beforeunload dialogs; in the latter, the windows will manage
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // showing their own dialogs.
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION ||
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      CommandLine::ForCurrentProcess()->HasSwitch(
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          switches::kDisableBatchedShutdown)) {
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CloseBrowsers();
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  TryToCloseBrowsers();
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::CancelBrowserClose() {
423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  browser_shutdown::SetTryingToQuit(false);
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    it->ResetBeforeUnloadHandlers();
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::TryToCloseBrowsers() {
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If all browser windows can immediately be closed, fall out of this loop and
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // close the browsers. If any browser window cannot be closed, temporarily
513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // stop closing. CallBeforeUnloadHandlers prompts the user and calls
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // OnBrowserReportCloseable with the result. If the user confirms the close,
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // this will trigger TryToCloseBrowsers to try again.
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (it->CallBeforeUnloadHandlers(
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            base::Bind(&BrowserCloseManager::OnBrowserReportCloseable, this))) {
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      current_browser_ = *it;
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return;
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CheckForDownloadsInProgress();
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::OnBrowserReportCloseable(bool proceed) {
653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!current_browser_)
663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  current_browser_ = NULL;
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (proceed)
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    TryToCloseBrowsers();
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  else
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CancelBrowserClose();
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::CheckForDownloadsInProgress() {
778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  int download_count = DownloadService::NonMaliciousDownloadCountAllProfiles();
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (download_count == 0) {
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CloseBrowsers();
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ConfirmCloseWithPendingDownloads(
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      download_count,
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&BrowserCloseManager::OnReportDownloadsCancellable, this));
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::ConfirmCloseWithPendingDownloads(
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int download_count,
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::Callback<void(bool)>& callback) {
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Browser* browser =
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      BrowserList::GetInstance(chrome::GetActiveDesktop())->GetLastActive();
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(browser);
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  browser->window()->ConfirmBrowserCloseWithPendingDownloads(
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      download_count,
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN,
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      true,
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      callback);
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::OnReportDownloadsCancellable(bool proceed) {
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (proceed) {
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CloseBrowsers();
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CancelBrowserClose();
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Open the downloads page for each profile with downloads in progress.
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<Profile*> profiles(
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      g_browser_process->profile_manager()->GetLoadedProfiles());
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (std::vector<Profile*>::iterator it = profiles.begin();
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       it != profiles.end();
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       ++it) {
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DownloadService* download_service =
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        DownloadServiceFactory::GetForBrowserContext(*it);
1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (download_service->NonMaliciousDownloadCount() > 0) {
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      Browser* browser =
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          chrome::FindOrCreateTabbedBrowser(*it, chrome::GetActiveDesktop());
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      DCHECK(browser);
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      chrome::ShowDownloads(browser);
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void BrowserCloseManager::CloseBrowsers() {
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Tell everyone that we are shutting down.
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  browser_shutdown::SetTryingToQuit(true);
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#if defined(ENABLE_SESSION_SERVICE)
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Before we close the browsers shutdown all session services. That way an
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // exit can restore all browsers open before exiting.
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ProfileManager::ShutdownSessionServices();
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#endif
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool session_ending =
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION;
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (scoped_ptr<chrome::BrowserIterator> it_ptr(
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           new chrome::BrowserIterator());
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       !it_ptr->done();) {
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    Browser* browser = **it_ptr;
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    browser->window()->Close();
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!session_ending) {
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      it_ptr->Next();
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    } else {
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // This path is hit during logoff/power-down. In this case we won't get
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // a final message and so we force the browser to be deleted.
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // Close doesn't immediately destroy the browser
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // (Browser::TabStripEmpty() uses invoke later) but when we're ending the
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // session we need to make sure the browser is destroyed now. So, invoke
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // DestroyBrowser to make sure the browser is deleted and cleanup can
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // happen.
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      while (browser->tab_strip_model()->count())
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        delete browser->tab_strip_model()->GetWebContentsAt(0);
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      browser->window()->DestroyBrowser();
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      it_ptr.reset(new chrome::BrowserIterator());
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (!it_ptr->done() && browser == **it_ptr) {
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // Destroying the browser should have removed it from the browser list.
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // We should never get here.
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        NOTREACHED();
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return;
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
165