Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/browser_list.h" | 5 #include "chrome/browser/ui/browser_list.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "base/metrics/histogram.h" | |
| 10 #include "base/observer_list.h" | |
| 11 #include "build/build_config.h" | |
| 12 #include "chrome/browser/browser_process.h" | |
| 13 #include "chrome/browser/browser_shutdown.h" | |
| 14 #include "chrome/browser/lifetime/application_lifetime.h" | |
| 15 #include "chrome/browser/prefs/pref_service.h" | |
| 16 #include "chrome/browser/profiles/profile.h" | 7 #include "chrome/browser/profiles/profile.h" |
| 17 #include "chrome/browser/ui/browser.h" | 8 #include "chrome/browser/ui/browser.h" |
| 18 #include "chrome/browser/ui/browser_window.h" | 9 #include "chrome/browser/ui/browser_list_impl.h" |
| 19 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 10 #include "chrome/browser/ui/browser_list_observer.h" |
|
jam
2012/07/12 18:53:22
this file isn't part of the change?
| |
| 20 #include "chrome/common/chrome_notification_types.h" | |
| 21 #include "chrome/common/chrome_switches.h" | |
| 22 #include "chrome/common/pref_names.h" | |
| 23 #include "content/public/browser/browser_shutdown.h" | |
| 24 #include "content/public/browser/browser_thread.h" | |
| 25 #include "content/public/browser/navigation_details.h" | |
| 26 #include "content/public/browser/notification_registrar.h" | |
| 27 #include "content/public/browser/notification_service.h" | |
| 28 #include "content/public/browser/render_process_host.h" | |
| 29 #include "content/public/common/result_codes.h" | |
| 30 | |
| 31 #if defined(OS_CHROMEOS) | |
| 32 #include "chrome/browser/chromeos/login/user_manager.h" | |
| 33 #endif | |
| 34 | 11 |
| 35 using content::WebContents; | 12 using content::WebContents; |
| 36 | 13 |
| 37 namespace browser { | |
| 38 | |
| 39 // This object is instantiated when the first Browser object is added to the | |
| 40 // list and delete when the last one is removed. It watches for loads and | |
| 41 // creates histograms of some global object counts. | |
| 42 class BrowserActivityObserver : public content::NotificationObserver { | |
| 43 public: | |
| 44 BrowserActivityObserver() { | |
| 45 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
| 46 content::NotificationService::AllSources()); | |
| 47 registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING, | |
| 48 content::NotificationService::AllSources()); | |
| 49 } | |
| 50 ~BrowserActivityObserver() {} | |
| 51 | |
| 52 private: | |
| 53 // content::NotificationObserver implementation. | |
| 54 virtual void Observe(int type, | |
| 55 const content::NotificationSource& source, | |
| 56 const content::NotificationDetails& details) { | |
| 57 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { | |
| 58 const content::LoadCommittedDetails& load = | |
| 59 *content::Details<content::LoadCommittedDetails>(details).ptr(); | |
| 60 if (!load.is_navigation_to_different_page()) | |
| 61 return; // Don't log for subframes or other trivial types. | |
| 62 | |
| 63 LogRenderProcessHostCount(); | |
| 64 LogBrowserTabCount(); | |
| 65 } else if (type == content::NOTIFICATION_APP_TERMINATING) { | |
| 66 delete this; | |
| 67 } | |
| 68 } | |
| 69 | |
| 70 // Counts the number of active RenderProcessHosts and logs them. | |
| 71 void LogRenderProcessHostCount() const { | |
| 72 int hosts_count = 0; | |
| 73 for (content::RenderProcessHost::iterator i( | |
| 74 content::RenderProcessHost::AllHostsIterator()); | |
| 75 !i.IsAtEnd(); i.Advance()) | |
| 76 ++hosts_count; | |
| 77 UMA_HISTOGRAM_CUSTOM_COUNTS("MPArch.RPHCountPerLoad", hosts_count, | |
| 78 1, 50, 50); | |
| 79 } | |
| 80 | |
| 81 // Counts the number of tabs in each browser window and logs them. This is | |
| 82 // different than the number of WebContents objects since WebContents objects | |
| 83 // can be used for popups and in dialog boxes. We're just counting toplevel | |
| 84 // tabs here. | |
| 85 void LogBrowserTabCount() const { | |
| 86 int tab_count = 0; | |
| 87 for (BrowserList::const_iterator browser_iterator = BrowserList::begin(); | |
| 88 browser_iterator != BrowserList::end(); browser_iterator++) { | |
| 89 // Record how many tabs each window has open. | |
| 90 Browser* browser = (*browser_iterator); | |
| 91 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerWindow", | |
| 92 browser->tab_count(), 1, 200, 50); | |
| 93 tab_count += browser->tab_count(); | |
| 94 | |
| 95 if (browser->window()->IsActive()) { | |
| 96 // Record how many tabs the active window has open. | |
| 97 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountActiveWindow", | |
| 98 browser->tab_count(), 1, 200, 50); | |
| 99 } | |
| 100 } | |
| 101 // Record how many tabs total are open (across all windows). | |
| 102 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerLoad", tab_count, 1, 200, 50); | |
| 103 } | |
| 104 | |
| 105 content::NotificationRegistrar registrar_; | |
| 106 | |
| 107 DISALLOW_COPY_AND_ASSIGN(BrowserActivityObserver); | |
| 108 }; | |
| 109 | |
| 110 BrowserActivityObserver* g_activity_observer = NULL; | |
| 111 | |
| 112 } // namespace browser | |
| 113 | |
| 114 namespace { | 14 namespace { |
| 115 | 15 |
| 116 static BrowserList::BrowserVector& browsers() { | 16 chrome::BrowserListImpl* GetNativeList() { |
| 117 CR_DEFINE_STATIC_LOCAL(BrowserList::BrowserVector, browser_vector, ()); | 17 return chrome::BrowserListImpl::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE); |
| 118 return browser_vector; | |
| 119 } | |
| 120 | |
| 121 static BrowserList::BrowserVector& last_active_browsers() { | |
| 122 CR_DEFINE_STATIC_LOCAL(BrowserList::BrowserVector, last_active_vector, ()); | |
| 123 return last_active_vector; | |
| 124 } | |
| 125 | |
| 126 static ObserverList<BrowserList::Observer>& observers() { | |
| 127 CR_DEFINE_STATIC_LOCAL( | |
| 128 ObserverList<BrowserList::Observer>, observer_vector, ()); | |
| 129 return observer_vector; | |
| 130 } | 18 } |
| 131 | 19 |
| 132 } // namespace | 20 } // namespace |
| 133 | 21 |
| 134 // static | 22 // static |
| 135 void BrowserList::AddBrowser(Browser* browser) { | 23 void BrowserList::AddBrowser(Browser* browser) { |
| 136 DCHECK(browser); | 24 GetNativeList()->AddBrowser(browser); |
| 137 browsers().push_back(browser); | |
| 138 | |
| 139 g_browser_process->AddRefModule(); | |
| 140 | |
| 141 if (!browser::g_activity_observer) | |
| 142 browser::g_activity_observer = new browser::BrowserActivityObserver; | |
| 143 | |
| 144 content::NotificationService::current()->Notify( | |
| 145 chrome::NOTIFICATION_BROWSER_OPENED, | |
| 146 content::Source<Browser>(browser), | |
| 147 content::NotificationService::NoDetails()); | |
| 148 | |
| 149 // Send out notifications after add has occurred. Do some basic checking to | |
| 150 // try to catch evil observers that change the list from under us. | |
| 151 size_t original_count = observers().size(); | |
| 152 FOR_EACH_OBSERVER(Observer, observers(), OnBrowserAdded(browser)); | |
| 153 DCHECK_EQ(original_count, observers().size()) | |
| 154 << "observer list modified during notification"; | |
| 155 } | 25 } |
| 156 | 26 |
| 157 // static | 27 // static |
| 158 void BrowserList::RemoveBrowser(Browser* browser) { | 28 void BrowserList::RemoveBrowser(Browser* browser) { |
| 159 RemoveBrowserFrom(browser, &last_active_browsers()); | 29 GetNativeList()->RemoveBrowser(browser); |
| 160 | |
| 161 // Many UI tests rely on closing the last browser window quitting the | |
| 162 // application. | |
| 163 // Mac: Closing all windows does not indicate quitting the application. Lie | |
| 164 // for now and ignore behavior outside of unit tests. | |
| 165 // ChromeOS: Force closing last window to close app with flag. | |
| 166 // TODO(andybons | pkotwicz): Fix the UI tests to Do The Right Thing. | |
| 167 #if defined(OS_CHROMEOS) | |
| 168 bool closing_app; | |
| 169 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 170 switches::kDisableZeroBrowsersOpenForTests)) | |
| 171 closing_app = (browsers().size() == 1); | |
| 172 else | |
| 173 closing_app = (browsers().size() == 1 && | |
| 174 browser_shutdown::IsTryingToQuit()); | |
| 175 #else | |
| 176 bool closing_app = (browsers().size() == 1); | |
| 177 #endif // OS_CHROMEOS | |
| 178 | |
| 179 content::NotificationService::current()->Notify( | |
| 180 chrome::NOTIFICATION_BROWSER_CLOSED, | |
| 181 content::Source<Browser>(browser), | |
| 182 content::Details<bool>(&closing_app)); | |
| 183 | |
| 184 RemoveBrowserFrom(browser, &browsers()); | |
| 185 | |
| 186 // Do some basic checking to try to catch evil observers | |
| 187 // that change the list from under us. | |
| 188 size_t original_count = observers().size(); | |
| 189 FOR_EACH_OBSERVER(Observer, observers(), OnBrowserRemoved(browser)); | |
| 190 DCHECK_EQ(original_count, observers().size()) | |
| 191 << "observer list modified during notification"; | |
| 192 | |
| 193 g_browser_process->ReleaseModule(); | |
| 194 | |
| 195 // If we're exiting, send out the APP_TERMINATING notification to allow other | |
| 196 // modules to shut themselves down. | |
| 197 if (browsers().empty() && | |
| 198 (browser_shutdown::IsTryingToQuit() || | |
| 199 g_browser_process->IsShuttingDown())) { | |
| 200 // Last browser has just closed, and this is a user-initiated quit or there | |
| 201 // is no module keeping the app alive, so send out our notification. No need | |
| 202 // to call ProfileManager::ShutdownSessionServices() as part of the | |
| 203 // shutdown, because Browser::WindowClosing() already makes sure that the | |
| 204 // SessionService is created and notified. | |
| 205 browser::NotifyAppTerminating(); | |
| 206 browser::OnAppExiting(); | |
| 207 } | |
| 208 } | 30 } |
| 209 | 31 |
| 210 // static | 32 // static |
| 211 void BrowserList::AddObserver(BrowserList::Observer* observer) { | 33 void BrowserList::AddObserver(chrome::BrowserListObserver* observer) { |
| 212 observers().AddObserver(observer); | 34 GetNativeList()->AddObserver(observer); |
| 213 } | 35 } |
| 214 | 36 |
| 215 // static | 37 // static |
| 216 void BrowserList::RemoveObserver(BrowserList::Observer* observer) { | 38 void BrowserList::RemoveObserver(chrome::BrowserListObserver* observer) { |
| 217 observers().RemoveObserver(observer); | 39 GetNativeList()->RemoveObserver(observer); |
| 218 } | 40 } |
| 219 | 41 |
| 220 void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) { | 42 void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) { |
| 221 BrowserVector browsers_to_close; | 43 GetNativeList()->CloseAllBrowsersWithProfile(profile); |
| 222 for (BrowserList::const_iterator i = BrowserList::begin(); | |
| 223 i != BrowserList::end(); ++i) { | |
| 224 if ((*i)->profile()->GetOriginalProfile() == profile->GetOriginalProfile()) | |
| 225 browsers_to_close.push_back(*i); | |
| 226 } | |
| 227 | |
| 228 for (BrowserVector::const_iterator i = browsers_to_close.begin(); | |
| 229 i != browsers_to_close.end(); ++i) { | |
| 230 (*i)->window()->Close(); | |
| 231 } | |
| 232 } | 44 } |
| 233 | 45 |
| 234 // static | 46 // static |
| 235 BrowserList::const_iterator BrowserList::begin() { | 47 BrowserList::const_iterator BrowserList::begin() { |
| 236 return browsers().begin(); | 48 return GetNativeList()->begin(); |
| 237 } | 49 } |
| 238 | 50 |
| 239 // static | 51 // static |
| 240 BrowserList::const_iterator BrowserList::end() { | 52 BrowserList::const_iterator BrowserList::end() { |
| 241 return browsers().end(); | 53 return GetNativeList()->end(); |
| 242 } | 54 } |
| 243 | 55 |
| 244 // static | 56 // static |
| 245 bool BrowserList::empty() { | 57 bool BrowserList::empty() { |
| 246 return browsers().empty(); | 58 return GetNativeList()->empty(); |
| 247 } | 59 } |
| 248 | 60 |
| 249 // static | 61 // static |
| 250 size_t BrowserList::size() { | 62 size_t BrowserList::size() { |
| 251 return browsers().size(); | 63 return GetNativeList()->size(); |
| 252 } | 64 } |
| 253 | 65 |
| 254 // static | 66 // static |
| 255 void BrowserList::SetLastActive(Browser* browser) { | 67 void BrowserList::SetLastActive(Browser* browser) { |
| 256 // If the browser is currently trying to quit, we don't want to set the last | 68 GetNativeList()->SetLastActive(browser); |
| 257 // active browser because that can alter the last active browser that the user | |
| 258 // intended depending on the order in which the windows close. | |
| 259 if (browser_shutdown::IsTryingToQuit()) | |
| 260 return; | |
| 261 RemoveBrowserFrom(browser, &last_active_browsers()); | |
| 262 last_active_browsers().push_back(browser); | |
| 263 | |
| 264 FOR_EACH_OBSERVER(Observer, observers(), OnBrowserSetLastActive(browser)); | |
| 265 } | 69 } |
| 266 | 70 |
| 267 // static | 71 // static |
| 268 BrowserList::const_reverse_iterator BrowserList::begin_last_active() { | 72 BrowserList::const_reverse_iterator BrowserList::begin_last_active() { |
| 269 return last_active_browsers().rbegin(); | 73 return GetNativeList()->begin_last_active(); |
| 270 } | 74 } |
| 271 | 75 |
| 272 // static | 76 // static |
| 273 BrowserList::const_reverse_iterator BrowserList::end_last_active() { | 77 BrowserList::const_reverse_iterator BrowserList::end_last_active() { |
| 274 return last_active_browsers().rend(); | 78 return GetNativeList()->end_last_active(); |
| 275 } | 79 } |
| 276 | 80 |
| 277 // static | 81 // static |
| 278 bool BrowserList::IsOffTheRecordSessionActive() { | 82 bool BrowserList::IsOffTheRecordSessionActive() { |
| 279 for (BrowserList::const_iterator i = BrowserList::begin(); | 83 return GetNativeList()->IsIncognitoWindowOpen(); |
| 280 i != BrowserList::end(); ++i) { | |
| 281 if ((*i)->profile()->IsOffTheRecord()) | |
| 282 return true; | |
| 283 } | |
| 284 return false; | |
| 285 } | 84 } |
| 286 | 85 |
| 287 // static | 86 // static |
| 288 bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile* profile) { | 87 bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile* profile) { |
| 289 #if defined(OS_CHROMEOS) | 88 return GetNativeList()->IsIncognitoWindowOpenForProfile(profile); |
| 290 // In ChromeOS, we assume that the default profile is always valid, so if | |
| 291 // we are in guest mode, keep the OTR profile active so it won't be deleted. | |
| 292 if (chromeos::UserManager::Get()->IsLoggedInAsGuest()) | |
| 293 return true; | |
| 294 #endif | |
| 295 for (BrowserList::const_iterator i = BrowserList::begin(); | |
| 296 i != BrowserList::end(); ++i) { | |
| 297 if ((*i)->profile()->IsSameProfile(profile) && | |
| 298 (*i)->profile()->IsOffTheRecord()) { | |
| 299 return true; | |
| 300 } | |
| 301 } | |
| 302 return false; | |
| 303 } | 89 } |
| 304 | 90 |
| 305 // static | 91 // static |
| 306 Browser* BrowserList::GetLastActive() { | 92 Browser* BrowserList::GetLastActive() { |
| 307 if (!last_active_browsers().empty()) | 93 return GetNativeList()->GetLastActive(); |
| 308 return *(last_active_browsers().rbegin()); | |
| 309 | |
| 310 return NULL; | |
| 311 } | 94 } |
| 312 | |
| 313 // static | |
| 314 void BrowserList::RemoveBrowserFrom(Browser* browser, | |
| 315 BrowserVector* browser_list) { | |
| 316 const iterator remove_browser = | |
| 317 std::find(browser_list->begin(), browser_list->end(), browser); | |
| 318 if (remove_browser != browser_list->end()) | |
| 319 browser_list->erase(remove_browser); | |
| 320 } | |
| 321 | |
| OLD | NEW |