1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_list.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
9731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_shutdown.h"
1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile_manager.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_window.h"
15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_process_host.h"
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_controller.h"
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_registrar.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/result_codes.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX)
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chrome_browser_application_mac.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#if defined(OS_CHROMEOS)
26201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/browser/chromeos/boot_times_loader.h"
2721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/chromeos/cros/cros_library.h"
2821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/chromeos/cros/login_library.h"
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/chromeos/cros/update_library.h"
303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "chrome/browser/chromeos/wm_ipc.h"
31201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#endif
32201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This object is instantiated when the first Browser object is added to the
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// list and delete when the last one is removed. It watches for loads and
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// creates histograms of some global object counts.
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass BrowserActivityObserver : public NotificationObserver {
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BrowserActivityObserver() {
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   NotificationService::AllSources());
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~BrowserActivityObserver() {}
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NotificationObserver implementation.
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Observe(NotificationType type,
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const NotificationSource& source,
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const NotificationDetails& details) {
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(type == NotificationType::NAV_ENTRY_COMMITTED);
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const NavigationController::LoadCommittedDetails& load =
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        *Details<NavigationController::LoadCommittedDetails>(details).ptr();
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!load.is_main_frame || load.is_auto || load.is_in_page)
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;  // Don't log for subframes or other trivial types.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LogRenderProcessHostCount();
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LogBrowserTabCount();
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Counts the number of active RenderProcessHosts and logs them.
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void LogRenderProcessHostCount() const {
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int hosts_count = 0;
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         !i.IsAtEnd(); i.Advance())
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++hosts_count;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_CUSTOM_COUNTS("MPArch.RPHCountPerLoad", hosts_count,
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                1, 50, 50);
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Counts the number of tabs in each browser window and logs them. This is
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // different than the number of TabContents objects since TabContents objects
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // can be used for popups and in dialog boxes. We're just counting toplevel
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // tabs here.
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void LogBrowserTabCount() const {
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int tab_count = 0;
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (BrowserList::const_iterator browser_iterator = BrowserList::begin();
784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch         browser_iterator != BrowserList::end(); browser_iterator++) {
794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      // Record how many tabs each window has open.
804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerWindow",
814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                  (*browser_iterator)->tab_count(), 1, 200, 50);
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_count += (*browser_iterator)->tab_count();
834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // Record how many tabs total are open (across all windows).
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerLoad", tab_count, 1, 200, 50);
864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    Browser* browser = BrowserList::GetLastActive();
884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (browser) {
894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      // Record how many tabs the active window has open.
904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountActiveWindow",
914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                  browser->tab_count(), 1, 200, 50);
924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationRegistrar registrar_;
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(BrowserActivityObserver);
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowserActivityObserver* activity_observer = NULL;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Type used to indicate only the type should be matched.
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kMatchNothing                 = 0;
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// See BrowserMatches for details.
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kMatchOriginalProfile         = 1 << 0;
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// See BrowserMatches for details.
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kMatchCanSupportWindowFeature = 1 << 1;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns true if the specified |browser| matches the specified arguments.
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |match_types| is a bitmask dictating what parameters to match:
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// . If it contains kMatchOriginalProfile then the original profile of the
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   browser must match |profile->GetOriginalProfile()|. This is used to match
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   incognito windows.
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// . If it contains kMatchCanSupportWindowFeature
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   |CanSupportWindowFeature(window_feature)| must return true.
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserMatches(Browser* browser,
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    Profile* profile,
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    Browser::Type type,
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    Browser::WindowFeature window_feature,
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    uint32 match_types) {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (match_types & kMatchCanSupportWindowFeature &&
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !browser->CanSupportWindowFeature(window_feature)) {
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (match_types & kMatchOriginalProfile) {
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (browser->profile()->GetOriginalProfile() !=
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        profile->GetOriginalProfile())
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (browser->profile() != profile) {
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type != Browser::TYPE_ANY && browser->type() != type)
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns the first browser in the specified iterator that returns true from
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |BrowserMatches|, or null if no browsers match the arguments. See
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |BrowserMatches| for details on the arguments.
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtemplate <class T>
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowser* FindBrowserMatching(const T& begin,
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             const T& end,
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             Profile* profile,
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             Browser::Type type,
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             Browser::WindowFeature window_feature,
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             uint32 match_types) {
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (T i = begin; i != end; ++i) {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (BrowserMatches(*i, profile, type, window_feature, match_types))
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return *i;
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return NULL;
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowserList::BrowserVector BrowserList::browsers_;
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochObserverList<BrowserList::Observer> BrowserList::observers_;
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserList::AddBrowser(Browser* browser) {
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(browser);
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browsers_.push_back(browser);
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_browser_process->AddRefModule();
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!activity_observer)
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    activity_observer = new BrowserActivityObserver;
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::BROWSER_OPENED,
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Source<Browser>(browser),
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::NoDetails());
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Send out notifications after add has occurred. Do some basic checking to
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // try to catch evil observers that change the list from under us.
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t original_count = observers_.size();
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FOR_EACH_OBSERVER(Observer, observers_, OnBrowserAdded(browser));
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(original_count, observers_.size())
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << "observer list modified during notification";
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
18872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BrowserList::MarkAsCleanShutdown() {
18972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (const_iterator i = begin(); i != end(); ++i) {
19072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    (*i)->profile()->MarkAsCleanShutdown();
19172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
19272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_CHROMEOS)
19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BrowserList::NotifyWindowManagerAboutSignout() {
19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  static bool notified = false;
19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!notified) {
19972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // Let the window manager know that we're going away before we start closing
20072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // windows so it can display a graceful transition to a black screen.
20172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    chromeos::WmIpc::instance()->NotifyAboutSignout();
20272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    notified = true;
20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
20472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
20572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
20672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
20772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool BrowserList::signout_ = false;
20872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
20972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif
21021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
21121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// static
21272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BrowserList::NotifyAndTerminate(bool fast_path) {
21321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(OS_CHROMEOS)
21472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!signout_) return;
21572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  NotifyWindowManagerAboutSignout();
21672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif
21772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (fast_path) {
21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    NotificationService::current()->Notify(NotificationType::APP_TERMINATING,
22072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                           NotificationService::AllSources(),
22172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                           NotificationService::NoDetails());
22272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
22372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
22472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_CHROMEOS)
22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  chromeos::CrosLibrary* cros_library = chromeos::CrosLibrary::Get();
22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (cros_library->EnsureLoaded()) {
22772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // If update has been installed, reboot, otherwise, sign out.
22872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (cros_library->GetUpdateLibrary()->status().status ==
22972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT) {
23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      cros_library->GetUpdateLibrary()->RebootAfterUpdate();
23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else {
23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      cros_library->GetLoginLibrary()->StopSession("");
23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
23421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return;
23521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
23621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // If running the Chrome OS build, but we're not on the device, fall through
23721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif
23821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  AllBrowsersClosedAndAppExiting();
23921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
24021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserList::RemoveBrowser(Browser* browser) {
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RemoveBrowserFrom(browser, &last_active_browsers_);
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Closing all windows does not indicate quitting the application on the Mac,
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // however, many UI tests rely on this behavior so leave it be for now and
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // simply ignore the behavior on the Mac outside of unit tests.
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(andybons): Fix the UI tests to Do The Right Thing.
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool closing_last_browser = (browsers_.size() == 1);
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::BROWSER_CLOSED,
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Source<Browser>(browser), Details<bool>(&closing_last_browser));
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
254731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  RemoveBrowserFrom(browser, &browsers_);
255731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
256731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Do some basic checking to try to catch evil observers
257731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // that change the list from under us.
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t original_count = observers_.size();
259731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  FOR_EACH_OBSERVER(Observer, observers_, OnBrowserRemoved(browser));
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(original_count, observers_.size())
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << "observer list modified during notification";
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the last Browser object was destroyed, make sure we try to close any
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // remaining dependent windows too.
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (browsers_.empty()) {
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete activity_observer;
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    activity_observer = NULL;
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_browser_process->ReleaseModule();
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we're exiting, send out the APP_TERMINATING notification to allow other
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // modules to shut themselves down.
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (browsers_.empty() &&
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (browser_shutdown::IsTryingToQuit() ||
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       g_browser_process->IsShuttingDown())) {
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Last browser has just closed, and this is a user-initiated quit or there
2783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // is no module keeping the app alive, so send out our notification. No need
2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // to call ProfileManager::ShutdownSessionServices() as part of the
2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // shutdown, because Browser::WindowClosing() already makes sure that the
2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // SessionService is created and notified.
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NotificationService::current()->Notify(NotificationType::APP_TERMINATING,
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           NotificationService::AllSources(),
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           NotificationService::NoDetails());
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AllBrowsersClosedAndAppExiting();
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserList::AddObserver(BrowserList::Observer* observer) {
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  observers_.AddObserver(observer);
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserList::RemoveObserver(BrowserList::Observer* observer) {
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  observers_.RemoveObserver(observer);
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
29921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(OS_CHROMEOS)
30021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// static
30121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool BrowserList::NeedBeforeUnloadFired() {
30221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  bool need_before_unload_fired = false;
30372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (const_iterator i = begin(); i != end(); ++i) {
30421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    need_before_unload_fired = need_before_unload_fired ||
30521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      (*i)->TabsNeedBeforeUnloadFired();
30621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
30721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return need_before_unload_fired;
30821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
30921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
31021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// static
31121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool BrowserList::PendingDownloads() {
31272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (const_iterator i = begin(); i != end(); ++i) {
31321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    bool normal_downloads_are_present = false;
31421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    bool incognito_downloads_are_present = false;
31521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    (*i)->CheckDownloadsInProgress(&normal_downloads_are_present,
31621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                   &incognito_downloads_are_present);
31721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (normal_downloads_are_present || incognito_downloads_are_present)
31821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return true;
31921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
32021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return false;
32121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
32221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif
32321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
3253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BrowserList::CloseAllBrowsers() {
3263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool session_ending =
3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION;
3283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool use_post = !session_ending;
3293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool force_exit = false;
3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(USE_X11)
3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (session_ending)
3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    force_exit = true;
3333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Tell everyone that we are shutting down.
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser_shutdown::SetTryingToQuit(true);
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Before we close the browsers shutdown all session services. That way an
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // exit can restore all browsers open before exiting.
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ProfileManager::ShutdownSessionServices();
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If there are no browsers, send the APP_TERMINATING action here. Otherwise,
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // it will be sent by RemoveBrowser() when the last browser has closed.
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (force_exit || browsers_.empty()) {
34472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    NotifyAndTerminate(true);
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
347201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#if defined(OS_CHROMEOS)
348201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker(
349201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      "StartedClosingWindows", false);
350201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#endif
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator i = BrowserList::begin();
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != BrowserList::end();) {
35321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    Browser* browser = *i;
35421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    browser->window()->Close();
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (use_post) {
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++i;
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This path is hit during logoff/power-down. In this case we won't get
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // a final message and so we force the browser to be deleted.
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Close doesn't immediately destroy the browser
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // (Browser::TabStripEmpty() uses invoke later) but when we're ending the
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // session we need to make sure the browser is destroyed now. So, invoke
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // DestroyBrowser to make sure the browser is deleted and cleanup can
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // happen.
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser->window()->DestroyBrowser();
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      i = BrowserList::begin();
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (i != BrowserList::end() && browser == *i) {
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Destroying the browser should have removed it from the browser list.
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // We should never get here.
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED();
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return;
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
37821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid BrowserList::Exit() {
37921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(OS_CHROMEOS)
38072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  signout_ = true;
38121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Fast shutdown for ChromeOS when there's no unload processing to be done.
38221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (chromeos::CrosLibrary::Get()->EnsureLoaded()
38321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      && !NeedBeforeUnloadFired()
38421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      && !PendingDownloads()) {
38572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    NotifyAndTerminate(true);
38621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return;
38721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
38821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif
38921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CloseAllBrowsersAndExit();
39021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
39121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
39221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// static
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserList::CloseAllBrowsersAndExit() {
39472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  MarkAsCleanShutdown();  // Don't notify users of crashes beyond this point.
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::APP_EXITING,
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::AllSources(),
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::NoDetails());
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if !defined(OS_MACOSX)
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // On most platforms, closing all windows causes the application to exit.
4023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CloseAllBrowsers();
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // On the Mac, the application continues to run once all windows are closed.
4053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Terminate will result in a CloseAllBrowsers() call, and once (and if)
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that is done, will cause the application to exit cleanly.
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  chrome_browser_application_mac::Terminate();
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
4124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid BrowserList::SessionEnding() {
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // EndSession is invoked once per frame. Only do something the first time.
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static bool already_ended = false;
41572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // We may get called in the middle of shutdown, e.g. http://crbug.com/70852
41672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // In this case, do nothing.
41772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (already_ended || !NotificationService::current())
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  already_ended = true;
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION);
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::APP_EXITING,
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::AllSources(),
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::NoDetails());
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Write important data first.
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_browser_process->EndSession();
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  BrowserList::CloseAllBrowsers();
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Send out notification. This is used during testing so that the test harness
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // can properly shutdown before we exit.
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::SESSION_END,
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::AllSources(),
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::NoDetails());
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // And shutdown.
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser_shutdown::Shutdown();
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // At this point the message loop is still running yet we've shut everything
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // down. If any messages are processed we'll likely crash. Exit now.
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExitProcess(ResultCodes::NORMAL_EXIT);
4473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#elif defined(OS_LINUX)
4483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  _exit(ResultCodes::NORMAL_EXIT);
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NOTIMPLEMENTED();
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserList::HasBrowserWithProfile(Profile* profile) {
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FindBrowserMatching(BrowserList::begin(),
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             BrowserList::end(),
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             profile, Browser::TYPE_ANY,
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             Browser::FEATURE_NONE,
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             kMatchNothing) != NULL;
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BrowserList::keep_alive_count_ = 0;
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserList::StartKeepAlive() {
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Increment the browser process refcount as long as we're keeping the
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // application alive.
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!WillKeepAlive())
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    g_browser_process->AddRefModule();
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  keep_alive_count_++;
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserList::EndKeepAlive() {
4774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  DCHECK_GT(keep_alive_count_, 0);
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  keep_alive_count_--;
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Allow the app to shutdown again.
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!WillKeepAlive()) {
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    g_browser_process->ReleaseModule();
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If there are no browsers open and we aren't already shutting down,
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // initiate a shutdown. Also skips shutdown if this is a unit test
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // (MessageLoop::current() == null).
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (browsers_.empty() && !browser_shutdown::IsTryingToQuit() &&
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        MessageLoop::current())
4873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      CloseAllBrowsers();
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserList::WillKeepAlive() {
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return keep_alive_count_ > 0;
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowserList::BrowserVector BrowserList::last_active_browsers_;
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserList::SetLastActive(Browser* browser) {
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RemoveBrowserFrom(browser, &last_active_browsers_);
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  last_active_browsers_.push_back(browser);
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FOR_EACH_OBSERVER(Observer, observers_, OnBrowserSetLastActive(browser));
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowser* BrowserList::GetLastActive() {
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!last_active_browsers_.empty())
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return *(last_active_browsers_.rbegin());
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return NULL;
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowser* BrowserList::GetLastActiveWithProfile(Profile* p) {
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We are only interested in last active browsers, so we don't fall back to
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // all browsers like FindBrowserWith* do.
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FindBrowserMatching(
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BrowserList::begin_last_active(), BrowserList::end_last_active(), p,
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Browser::TYPE_ANY, Browser::FEATURE_NONE, kMatchNothing);
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowser* BrowserList::FindBrowserWithType(Profile* p, Browser::Type t,
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          bool match_incognito) {
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  uint32 match_types = match_incognito ? kMatchOriginalProfile : kMatchNothing;
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = FindBrowserMatching(
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BrowserList::begin_last_active(), BrowserList::end_last_active(),
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      p, t, Browser::FEATURE_NONE, match_types);
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Fall back to a forward scan of all Browsers if no active one was found.
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return browser ? browser :
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FindBrowserMatching(BrowserList::begin(), BrowserList::end(), p, t,
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          Browser::FEATURE_NONE, match_types);
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowser* BrowserList::FindBrowserWithFeature(Profile* p,
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             Browser::WindowFeature feature) {
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = FindBrowserMatching(
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BrowserList::begin_last_active(), BrowserList::end_last_active(),
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      p, Browser::TYPE_ANY, feature, kMatchCanSupportWindowFeature);
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Fall back to a forward scan of all Browsers if no active one was found.
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return browser ? browser :
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FindBrowserMatching(BrowserList::begin(), BrowserList::end(), p,
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          Browser::TYPE_ANY, feature,
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          kMatchCanSupportWindowFeature);
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowser* BrowserList::FindBrowserWithProfile(Profile* p) {
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FindBrowserWithType(p, Browser::TYPE_ANY, false);
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBrowser* BrowserList::FindBrowserWithID(SessionID::id_type desired_id) {
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator i = BrowserList::begin();
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != BrowserList::end(); ++i) {
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((*i)->session_id().id() == desired_id)
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return *i;
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return NULL;
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t BrowserList::GetBrowserCountForType(Profile* p, Browser::Type type) {
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t result = 0;
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator i = BrowserList::begin();
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != BrowserList::end(); ++i) {
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (BrowserMatches(*i, p, type, Browser::FEATURE_NONE, kMatchNothing))
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++result;
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t BrowserList::GetBrowserCount(Profile* p) {
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t result = 0;
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator i = BrowserList::begin();
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != BrowserList::end(); ++i) {
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (BrowserMatches(*i, p, Browser::TYPE_ANY, Browser::FEATURE_NONE,
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       kMatchNothing)) {
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      result++;
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BrowserList::IsOffTheRecordSessionActive() {
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator i = BrowserList::begin();
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != BrowserList::end(); ++i) {
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((*i)->profile()->IsOffTheRecord())
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BrowserList::RemoveBrowserFrom(Browser* browser,
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    BrowserVector* browser_list) {
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const iterator remove_browser =
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::find(browser_list->begin(), browser_list->end(), browser);
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (remove_browser != browser_list->end())
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser_list->erase(remove_browser);
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabContentsIterator::TabContentsIterator()
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : browser_iterator_(BrowserList::begin()),
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      web_view_index_(-1),
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cur_(NULL) {
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Advance();
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabContentsIterator::Advance() {
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Unless we're at the beginning (index = -1) or end (iterator = end()),
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // then the current TabContents should be valid.
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(web_view_index_ || browser_iterator_ == BrowserList::end() || cur_)
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << "Trying to advance past the end";
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update cur_ to the next TabContents in the list.
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (browser_iterator_ != BrowserList::end()) {
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_view_index_++;
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    while (web_view_index_ >= (*browser_iterator_)->tab_count()) {
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // advance browsers
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++browser_iterator_;
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      web_view_index_ = 0;
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (browser_iterator_ == BrowserList::end()) {
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        cur_ = NULL;
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return;
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
635ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    TabContentsWrapper* next_tab =
636ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        (*browser_iterator_)->GetTabContentsWrapperAt(web_view_index_);
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (next_tab) {
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cur_ = next_tab;
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
643