Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(376)

Side by Side Diff: chrome/browser/lifetime/application_lifetime.cc

Issue 10409022: Move application lifetime functionality off BrowserList. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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" 7 #include "base/command_line.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/metrics/histogram.h"
11 #include "build/build_config.h" 10 #include "build/build_config.h"
12 #include "chrome/browser/browser_process.h" 11 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/browser_shutdown.h" 12 #include "chrome/browser/browser_shutdown.h"
14 #include "chrome/browser/download/download_service.h" 13 #include "chrome/browser/download/download_service.h"
15 #include "chrome/browser/metrics/thread_watcher.h" 14 #include "chrome/browser/metrics/thread_watcher.h"
16 #include "chrome/browser/prefs/pref_service.h" 15 #include "chrome/browser/prefs/pref_service.h"
17 #include "chrome/browser/printing/background_printing_manager.h"
18 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/profiles/profile_manager.h" 17 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_window.h" 19 #include "chrome/browser/ui/browser_window.h"
22 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
23 #include "chrome/common/chrome_notification_types.h" 21 #include "chrome/common/chrome_notification_types.h"
24 #include "chrome/common/chrome_switches.h" 22 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/pref_names.h" 23 #include "chrome/common/pref_names.h"
26 #include "content/public/browser/browser_shutdown.h" 24 #include "content/public/browser/browser_shutdown.h"
27 #include "content/public/browser/browser_thread.h" 25 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/navigation_details.h" 26 #include "content/public/browser/navigation_details.h"
29 #include "content/public/browser/notification_registrar.h"
30 #include "content/public/browser/notification_service.h" 27 #include "content/public/browser/notification_service.h"
31 #include "content/public/browser/render_process_host.h"
32 #include "content/public/common/result_codes.h"
33 28
34 #if defined(OS_MACOSX) 29 #if defined(OS_MACOSX)
35 #include "chrome/browser/chrome_browser_application_mac.h" 30 #include "chrome/browser/chrome_browser_application_mac.h"
36 #endif 31 #endif
37 32
38 #if defined(OS_CHROMEOS) 33 #if defined(OS_CHROMEOS)
39 #include "base/chromeos/chromeos_version.h" 34 #include "base/chromeos/chromeos_version.h"
40 #include "chrome/browser/chromeos/boot_times_loader.h" 35 #include "chrome/browser/chromeos/boot_times_loader.h"
41 #include "chrome/browser/chromeos/login/user_manager.h" 36 #include "chrome/browser/chromeos/login/user_manager.h"
42 #include "chromeos/dbus/dbus_thread_manager.h" 37 #include "chromeos/dbus/dbus_thread_manager.h"
43 #include "chromeos/dbus/session_manager_client.h" 38 #include "chromeos/dbus/session_manager_client.h"
44 #include "chromeos/dbus/update_engine_client.h" 39 #include "chromeos/dbus/update_engine_client.h"
45 #endif 40 #endif
46 41
47 using content::WebContents; 42 namespace browser {
48
49 namespace { 43 namespace {
50 44
51 // This object is instantiated when the first Browser object is added to the
52 // list and delete when the last one is removed. It watches for loads and
53 // creates histograms of some global object counts.
54 class BrowserActivityObserver : public content::NotificationObserver {
55 public:
56 BrowserActivityObserver() {
57 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
58 content::NotificationService::AllSources());
59 }
60 ~BrowserActivityObserver() {}
61
62 private:
63 // content::NotificationObserver implementation.
64 virtual void Observe(int type,
65 const content::NotificationSource& source,
66 const content::NotificationDetails& details) {
67 DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED);
68 const content::LoadCommittedDetails& load =
69 *content::Details<content::LoadCommittedDetails>(details).ptr();
70 if (!load.is_navigation_to_different_page())
71 return; // Don't log for subframes or other trivial types.
72
73 LogRenderProcessHostCount();
74 LogBrowserTabCount();
75 }
76
77 // Counts the number of active RenderProcessHosts and logs them.
78 void LogRenderProcessHostCount() const {
79 int hosts_count = 0;
80 for (content::RenderProcessHost::iterator i(
81 content::RenderProcessHost::AllHostsIterator());
82 !i.IsAtEnd(); i.Advance())
83 ++hosts_count;
84 UMA_HISTOGRAM_CUSTOM_COUNTS("MPArch.RPHCountPerLoad", hosts_count,
85 1, 50, 50);
86 }
87
88 // Counts the number of tabs in each browser window and logs them. This is
89 // different than the number of WebContents objects since WebContents objects
90 // can be used for popups and in dialog boxes. We're just counting toplevel
91 // tabs here.
92 void LogBrowserTabCount() const {
93 int tab_count = 0;
94 for (BrowserList::const_iterator browser_iterator = BrowserList::begin();
95 browser_iterator != BrowserList::end(); browser_iterator++) {
96 // Record how many tabs each window has open.
97 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerWindow",
98 (*browser_iterator)->tab_count(), 1, 200, 50);
99 tab_count += (*browser_iterator)->tab_count();
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 Browser* browser = BrowserList::GetLastActive();
105 if (browser) {
106 // Record how many tabs the active window has open.
107 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountActiveWindow",
108 browser->tab_count(), 1, 200, 50);
109 }
110 }
111
112 content::NotificationRegistrar registrar_;
113
114 DISALLOW_COPY_AND_ASSIGN(BrowserActivityObserver);
115 };
116
117 BrowserActivityObserver* activity_observer = NULL;
118
119 static BrowserList::BrowserVector& browsers() {
120 CR_DEFINE_STATIC_LOCAL(BrowserList::BrowserVector, browser_vector, ());
121 return browser_vector;
122 }
123
124 static BrowserList::BrowserVector& last_active_browsers() {
125 CR_DEFINE_STATIC_LOCAL(BrowserList::BrowserVector, last_active_vector, ());
126 return last_active_vector;
127 }
128
129 static ObserverList<BrowserList::Observer>& observers() {
130 CR_DEFINE_STATIC_LOCAL(
131 ObserverList<BrowserList::Observer>, observer_vector, ());
132 return observer_vector;
133 }
134
135 printing::BackgroundPrintingManager* GetBackgroundPrintingManager() {
136 return g_browser_process->background_printing_manager();
137 }
138
139 // Returns true if all browsers can be closed without user interaction. 45 // Returns true if all browsers can be closed without user interaction.
140 // This currently checks if there is pending download, or if it needs to 46 // This currently checks if there is pending download, or if it needs to
141 // handle unload handler. 47 // handle unload handler.
142 bool AreAllBrowsersCloseable() { 48 bool AreAllBrowsersCloseable() {
143 BrowserList::const_iterator browser_it = BrowserList::begin(); 49 BrowserList::const_iterator browser_it = BrowserList::begin();
144 if (browser_it == BrowserList::end()) 50 if (browser_it == BrowserList::end())
145 return true; 51 return true;
146 52
147 // If there are any downloads active, all browsers are not closeable. 53 // If there are any downloads active, all browsers are not closeable.
148 if (DownloadService::DownloadCountAllProfiles() > 0) 54 if (DownloadService::DownloadCountAllProfiles() > 0)
149 return false; 55 return false;
150 56
151 // Check TabsNeedBeforeUnloadFired(). 57 // Check TabsNeedBeforeUnloadFired().
152 for (; browser_it != BrowserList::end(); ++browser_it) { 58 for (; browser_it != BrowserList::end(); ++browser_it) {
153 if ((*browser_it)->TabsNeedBeforeUnloadFired()) 59 if ((*browser_it)->TabsNeedBeforeUnloadFired())
154 return false; 60 return false;
155 } 61 }
156 return true; 62 return true;
157 } 63 }
158 64
159 // Emits APP_TERMINATING notification. It is guaranteed that the 65 int g_keep_alive_count = 0;
160 // notification is sent only once.
161 void NotifyAppTerminating() {
162 static bool notified = false;
163 if (notified)
164 return;
165 notified = true;
166 content::NotificationService::current()->Notify(
167 content::NOTIFICATION_APP_TERMINATING,
168 content::NotificationService::AllSources(),
169 content::NotificationService::NoDetails());
170 }
171 66
172 #if defined(OS_CHROMEOS) 67 #if defined(OS_CHROMEOS)
173 // Whether a session manager requested to shutdown. 68 // Whether a session manager requested to shutdown.
174 bool g_session_manager_requested_shutdown = true; 69 bool g_session_manager_requested_shutdown = true;
175 #endif 70 #endif
176 71
177 } // namespace 72 } // namespace
178 73
179 // static 74 void MarkAsCleanShutdown() {
180 void BrowserList::AddBrowser(Browser* browser) { 75 // TODO(beng): Can this use ProfileManager::GetLoadedProfiles() instead?
181 DCHECK(browser); 76 for (BrowserList::const_iterator i = BrowserList::begin();
182 browsers().push_back(browser); 77 i != BrowserList::end(); ++i) {
183
184 g_browser_process->AddRefModule();
185
186 if (!activity_observer)
187 activity_observer = new BrowserActivityObserver;
188
189 content::NotificationService::current()->Notify(
190 chrome::NOTIFICATION_BROWSER_OPENED,
191 content::Source<Browser>(browser),
192 content::NotificationService::NoDetails());
193
194 // Send out notifications after add has occurred. Do some basic checking to
195 // try to catch evil observers that change the list from under us.
196 size_t original_count = observers().size();
197 FOR_EACH_OBSERVER(Observer, observers(), OnBrowserAdded(browser));
198 DCHECK_EQ(original_count, observers().size())
199 << "observer list modified during notification";
200 }
201
202 // static
203 void BrowserList::MarkAsCleanShutdown() {
204 for (const_iterator i = begin(); i != end(); ++i) {
205 (*i)->profile()->MarkAsCleanShutdown(); 78 (*i)->profile()->MarkAsCleanShutdown();
206 } 79 }
207 } 80 }
208 81
209 void BrowserList::AttemptExitInternal() { 82 void AttemptExitInternal() {
210 content::NotificationService::current()->Notify( 83 content::NotificationService::current()->Notify(
211 content::NOTIFICATION_APP_EXITING, 84 content::NOTIFICATION_APP_EXITING,
212 content::NotificationService::AllSources(), 85 content::NotificationService::AllSources(),
213 content::NotificationService::NoDetails()); 86 content::NotificationService::NoDetails());
214 87
215 #if !defined(OS_MACOSX) 88 #if !defined(OS_MACOSX)
216 // On most platforms, closing all windows causes the application to exit. 89 // On most platforms, closing all windows causes the application to exit.
217 CloseAllBrowsers(); 90 CloseAllBrowsers();
218 #else 91 #else
219 // On the Mac, the application continues to run once all windows are closed. 92 // On the Mac, the application continues to run once all windows are closed.
220 // Terminate will result in a CloseAllBrowsers() call, and once (and if) 93 // Terminate will result in a CloseAllBrowsers() call, and once (and if)
221 // that is done, will cause the application to exit cleanly. 94 // that is done, will cause the application to exit cleanly.
222 chrome_browser_application_mac::Terminate(); 95 chrome_browser_application_mac::Terminate();
223 #endif 96 #endif
224 } 97 }
225 98
226 // static 99 void NotifyAppTerminating() {
227 void BrowserList::NotifyAndTerminate(bool fast_path) { 100 static bool notified = false;
101 if (notified)
102 return;
103 notified = true;
104 content::NotificationService::current()->Notify(
105 content::NOTIFICATION_APP_TERMINATING,
106 content::NotificationService::AllSources(),
107 content::NotificationService::NoDetails());
108 }
109
110 void NotifyAndTerminate(bool fast_path) {
228 #if defined(OS_CHROMEOS) 111 #if defined(OS_CHROMEOS)
229 static bool notified = false; 112 static bool notified = false;
230 // Don't ask SessionManager to shutdown if 113 // Don't ask SessionManager to shutdown if
231 // a) a shutdown request has already been sent. 114 // a) a shutdown request has already been sent.
232 // b) shutdown request comes from session manager. 115 // b) shutdown request comes from session manager.
233 if (notified || g_session_manager_requested_shutdown) 116 if (notified || g_session_manager_requested_shutdown)
234 return; 117 return;
235 notified = true; 118 notified = true;
236 #endif 119 #endif
237 120
(...skipping 10 matching lines...) Expand all
248 chromeos::UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) { 131 chromeos::UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) {
249 update_engine_client->RebootAfterUpdate(); 132 update_engine_client->RebootAfterUpdate();
250 } else { 133 } else {
251 chromeos::DBusThreadManager::Get()->GetSessionManagerClient() 134 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()
252 ->StopSession(); 135 ->StopSession();
253 } 136 }
254 } else { 137 } else {
255 // If running the Chrome OS build, but we're not on the device, act 138 // If running the Chrome OS build, but we're not on the device, act
256 // as if we received signal from SessionManager. 139 // as if we received signal from SessionManager.
257 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 140 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
258 base::Bind(&BrowserList::ExitCleanly)); 141 base::Bind(&browser::ExitCleanly));
259 } 142 }
260 #endif 143 #endif
261 } 144 }
262 145
263 void BrowserList::OnAppExiting() { 146 void OnAppExiting() {
264 static bool notified = false; 147 static bool notified = false;
265 if (notified) 148 if (notified)
266 return; 149 return;
267 notified = true; 150 notified = true;
268
269 delete activity_observer;
270 activity_observer = NULL;
271 HandleAppExitingForPlatform(); 151 HandleAppExitingForPlatform();
272 } 152 }
273 153
274 // static 154 void CloseAllBrowsers() {
275 void BrowserList::RemoveBrowser(Browser* browser) {
276 RemoveBrowserFrom(browser, &last_active_browsers());
277
278 // Many UI tests rely on closing the last browser window quitting the
279 // application.
280 // Mac: Closing all windows does not indicate quitting the application. Lie
281 // for now and ignore behavior outside of unit tests.
282 // ChromeOS: Force closing last window to close app with flag.
283 // TODO(andybons | pkotwicz): Fix the UI tests to Do The Right Thing.
284 #if defined(OS_CHROMEOS)
285 bool closing_app;
286 if (CommandLine::ForCurrentProcess()->HasSwitch(
287 switches::kDisableZeroBrowsersOpenForTests))
288 closing_app = (browsers().size() == 1);
289 else
290 closing_app = (browsers().size() == 1 &&
291 browser_shutdown::IsTryingToQuit());
292 #else
293 bool closing_app = (browsers().size() == 1);
294 #endif // OS_CHROMEOS
295
296 content::NotificationService::current()->Notify(
297 chrome::NOTIFICATION_BROWSER_CLOSED,
298 content::Source<Browser>(browser),
299 content::Details<bool>(&closing_app));
300
301 RemoveBrowserFrom(browser, &browsers());
302
303 // Do some basic checking to try to catch evil observers
304 // that change the list from under us.
305 size_t original_count = observers().size();
306 FOR_EACH_OBSERVER(Observer, observers(), OnBrowserRemoved(browser));
307 DCHECK_EQ(original_count, observers().size())
308 << "observer list modified during notification";
309
310 g_browser_process->ReleaseModule();
311
312 // If we're exiting, send out the APP_TERMINATING notification to allow other
313 // modules to shut themselves down.
314 if (browsers().empty() &&
315 (browser_shutdown::IsTryingToQuit() ||
316 g_browser_process->IsShuttingDown())) {
317 // Last browser has just closed, and this is a user-initiated quit or there
318 // is no module keeping the app alive, so send out our notification. No need
319 // to call ProfileManager::ShutdownSessionServices() as part of the
320 // shutdown, because Browser::WindowClosing() already makes sure that the
321 // SessionService is created and notified.
322 NotifyAppTerminating();
323 OnAppExiting();
324 }
325 }
326
327 // static
328 void BrowserList::AddObserver(BrowserList::Observer* observer) {
329 observers().AddObserver(observer);
330 }
331
332 // static
333 void BrowserList::RemoveObserver(BrowserList::Observer* observer) {
334 observers().RemoveObserver(observer);
335 }
336
337 // static
338 void BrowserList::CloseAllBrowsers() {
339 bool session_ending = 155 bool session_ending =
340 browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION; 156 browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION;
341 // Tell everyone that we are shutting down. 157 // Tell everyone that we are shutting down.
342 browser_shutdown::SetTryingToQuit(true); 158 browser_shutdown::SetTryingToQuit(true);
343 159
344 // Before we close the browsers shutdown all session services. That way an 160 // Before we close the browsers shutdown all session services. That way an
345 // exit can restore all browsers open before exiting. 161 // exit can restore all browsers open before exiting.
346 ProfileManager::ShutdownSessionServices(); 162 ProfileManager::ShutdownSessionServices();
347 163
348 // If there are no browsers, send the APP_TERMINATING action here. Otherwise, 164 // If there are no browsers, send the APP_TERMINATING action here. Otherwise,
349 // it will be sent by RemoveBrowser() when the last browser has closed. 165 // it will be sent by RemoveBrowser() when the last browser has closed.
350 if (browser_shutdown::ShuttingDownWithoutClosingBrowsers() || 166 if (browser_shutdown::ShuttingDownWithoutClosingBrowsers() ||
351 browsers().empty()) { 167 BrowserList::empty()) {
352 NotifyAndTerminate(true); 168 NotifyAndTerminate(true);
353 OnAppExiting(); 169 OnAppExiting();
354 return; 170 return;
355 } 171 }
356 172
357 #if defined(OS_CHROMEOS) 173 #if defined(OS_CHROMEOS)
358 chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker( 174 chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker(
359 "StartedClosingWindows", false); 175 "StartedClosingWindows", false);
360 #endif 176 #endif
361 for (BrowserList::const_iterator i = BrowserList::begin(); 177 for (BrowserList::const_iterator i = BrowserList::begin();
(...skipping 17 matching lines...) Expand all
379 if (i != BrowserList::end() && browser == *i) { 195 if (i != BrowserList::end() && browser == *i) {
380 // Destroying the browser should have removed it from the browser list. 196 // Destroying the browser should have removed it from the browser list.
381 // We should never get here. 197 // We should never get here.
382 NOTREACHED(); 198 NOTREACHED();
383 return; 199 return;
384 } 200 }
385 } 201 }
386 } 202 }
387 } 203 }
388 204
389 void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) { 205 void AttemptUserExit() {
390 BrowserVector browsers_to_close;
391 for (BrowserList::const_iterator i = BrowserList::begin();
392 i != BrowserList::end(); ++i) {
393 if ((*i)->profile()->GetOriginalProfile() == profile->GetOriginalProfile())
394 browsers_to_close.push_back(*i);
395 }
396
397 for (BrowserVector::const_iterator i = browsers_to_close.begin();
398 i != browsers_to_close.end(); ++i) {
399 (*i)->window()->Close();
400 }
401 }
402
403 // static
404 void BrowserList::AttemptUserExit() {
405 #if defined(OS_CHROMEOS) 206 #if defined(OS_CHROMEOS)
406 chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutStarted", false); 207 chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutStarted", false);
407 // Write /tmp/uptime-logout-started as well. 208 // Write /tmp/uptime-logout-started as well.
408 const char kLogoutStarted[] = "logout-started"; 209 const char kLogoutStarted[] = "logout-started";
409 chromeos::BootTimesLoader::Get()->RecordCurrentStats(kLogoutStarted); 210 chromeos::BootTimesLoader::Get()->RecordCurrentStats(kLogoutStarted);
410 211
411 // Login screen should show up in owner's locale. 212 // Login screen should show up in owner's locale.
412 PrefService* state = g_browser_process->local_state(); 213 PrefService* state = g_browser_process->local_state();
413 if (state) { 214 if (state) {
414 std::string owner_locale = state->GetString(prefs::kOwnerLocale); 215 std::string owner_locale = state->GetString(prefs::kOwnerLocale);
415 if (!owner_locale.empty() && 216 if (!owner_locale.empty() &&
416 state->GetString(prefs::kApplicationLocale) != owner_locale && 217 state->GetString(prefs::kApplicationLocale) != owner_locale &&
417 !state->IsManagedPreference(prefs::kApplicationLocale)) { 218 !state->IsManagedPreference(prefs::kApplicationLocale)) {
418 state->SetString(prefs::kApplicationLocale, owner_locale); 219 state->SetString(prefs::kApplicationLocale, owner_locale);
419 state->CommitPendingWrite(); 220 state->CommitPendingWrite();
420 } 221 }
421 } 222 }
422 g_session_manager_requested_shutdown = false; 223 g_session_manager_requested_shutdown = false;
423 // On ChromeOS, always terminate the browser, regardless of the result of 224 // On ChromeOS, always terminate the browser, regardless of the result of
424 // AreAllBrowsersCloseable(). See crbug.com/123107. 225 // AreAllBrowsersCloseable(). See crbug.com/123107.
425 BrowserList::NotifyAndTerminate(true); 226 NotifyAndTerminate(true);
426 #else 227 #else
427 // Reset the restart bit that might have been set in cancelled restart 228 // Reset the restart bit that might have been set in cancelled restart
428 // request. 229 // request.
429 PrefService* pref_service = g_browser_process->local_state(); 230 PrefService* pref_service = g_browser_process->local_state();
430 pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, false); 231 pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, false);
431 AttemptExitInternal(); 232 AttemptExitInternal();
432 #endif 233 #endif
433 } 234 }
434 235
435 // static 236 void AttemptRestart() {
436 void BrowserList::AttemptRestart() {
437 if (!CommandLine::ForCurrentProcess()->HasSwitch( 237 if (!CommandLine::ForCurrentProcess()->HasSwitch(
438 switches::kDisableRestoreSessionState)) { 238 switches::kDisableRestoreSessionState)) {
439 BrowserVector::const_iterator it; 239 // TODO(beng): Can this use ProfileManager::GetLoadedProfiles instead?
440 for (it = begin(); it != end(); ++it) 240 BrowserList::const_iterator it;
241 for (it = BrowserList::begin(); it != BrowserList::end(); ++it)
441 content::BrowserContext::SaveSessionState((*it)->profile()); 242 content::BrowserContext::SaveSessionState((*it)->profile());
442 } 243 }
443 244
444 PrefService* pref_service = g_browser_process->local_state(); 245 PrefService* pref_service = g_browser_process->local_state();
445 pref_service->SetBoolean(prefs::kWasRestarted, true); 246 pref_service->SetBoolean(prefs::kWasRestarted, true);
446 247
447 #if defined(OS_CHROMEOS) 248 #if defined(OS_CHROMEOS)
448 // For CrOS instead of browser restart (which is not supported) perform a full 249 // For CrOS instead of browser restart (which is not supported) perform a full
449 // sign out. Session will be only restored if user has that setting set. 250 // sign out. Session will be only restored if user has that setting set.
450 // Same session restore behavior happens in case of full restart after update. 251 // Same session restore behavior happens in case of full restart after update.
451 AttemptUserExit(); 252 AttemptUserExit();
452 #else 253 #else
453 // Set the flag to restore state after the restart. 254 // Set the flag to restore state after the restart.
454 pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true); 255 pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true);
455 AttemptExit(); 256 AttemptExit();
456 #endif 257 #endif
457 } 258 }
458 259
459 // static 260 void AttemptExit() {
460 void BrowserList::AttemptExit() {
461 // If we know that all browsers can be closed without blocking, 261 // If we know that all browsers can be closed without blocking,
462 // don't notify users of crashes beyond this point. 262 // don't notify users of crashes beyond this point.
463 // Note that MarkAsCleanShutdown does not set UMA's exit cleanly bit 263 // Note that MarkAsCleanShutdown does not set UMA's exit cleanly bit
464 // so crashes during shutdown are still reported in UMA. 264 // so crashes during shutdown are still reported in UMA.
465 if (AreAllBrowsersCloseable()) 265 if (AreAllBrowsersCloseable())
466 MarkAsCleanShutdown(); 266 MarkAsCleanShutdown();
467 AttemptExitInternal(); 267 AttemptExitInternal();
468 } 268 }
469 269
470 #if defined(OS_CHROMEOS) 270 #if defined(OS_CHROMEOS)
471 // A function called when SIGTERM is received. 271 // A function called when SIGTERM is received.
472 // static 272 void ExitCleanly() {
473 void BrowserList::ExitCleanly() {
474 // We always mark exit cleanly because SessionManager may kill 273 // We always mark exit cleanly because SessionManager may kill
475 // chrome in 3 seconds after SIGTERM. 274 // chrome in 3 seconds after SIGTERM.
476 g_browser_process->EndSession(); 275 g_browser_process->EndSession();
477 276
478 // Don't block when SIGTERM is received. AreaAllBrowsersCloseable() 277 // Don't block when SIGTERM is received. AreaAllBrowsersCloseable()
479 // can be false in following cases. a) power-off b) signout from 278 // can be false in following cases. a) power-off b) signout from
480 // screen locker. 279 // screen locker.
481 if (!AreAllBrowsersCloseable()) 280 if (!AreAllBrowsersCloseable())
482 browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION); 281 browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION);
483 AttemptExitInternal(); 282 AttemptExitInternal();
484 } 283 }
485 #endif 284 #endif
486 285
487 // static 286 void SessionEnding() {
488 void BrowserList::SessionEnding() {
489 // This is a time-limited shutdown where we need to write as much to 287 // This is a time-limited shutdown where we need to write as much to
490 // disk as we can as soon as we can, and where we must kill the 288 // disk as we can as soon as we can, and where we must kill the
491 // process within a hang timeout to avoid user prompts. 289 // process within a hang timeout to avoid user prompts.
492 290
493 // Start watching for hang during shutdown, and crash it if takes too long. 291 // Start watching for hang during shutdown, and crash it if takes too long.
494 // We disarm when |shutdown_watcher| object is destroyed, which is when we 292 // We disarm when |shutdown_watcher| object is destroyed, which is when we
495 // exit this function. 293 // exit this function.
496 ShutdownWatcherHelper shutdown_watcher; 294 ShutdownWatcherHelper shutdown_watcher;
497 shutdown_watcher.Arm(base::TimeDelta::FromSeconds(90)); 295 shutdown_watcher.Arm(base::TimeDelta::FromSeconds(90));
498 296
499 // EndSession is invoked once per frame. Only do something the first time. 297 // EndSession is invoked once per frame. Only do something the first time.
500 static bool already_ended = false; 298 static bool already_ended = false;
501 // We may get called in the middle of shutdown, e.g. http://crbug.com/70852 299 // We may get called in the middle of shutdown, e.g. http://crbug.com/70852
502 // In this case, do nothing. 300 // In this case, do nothing.
503 if (already_ended || !content::NotificationService::current()) 301 if (already_ended || !content::NotificationService::current())
504 return; 302 return;
505 already_ended = true; 303 already_ended = true;
506 304
507 browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION); 305 browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION);
508 306
509 content::NotificationService::current()->Notify( 307 content::NotificationService::current()->Notify(
510 content::NOTIFICATION_APP_EXITING, 308 content::NOTIFICATION_APP_EXITING,
511 content::NotificationService::AllSources(), 309 content::NotificationService::AllSources(),
512 content::NotificationService::NoDetails()); 310 content::NotificationService::NoDetails());
513 311
514 // Write important data first. 312 // Write important data first.
515 g_browser_process->EndSession(); 313 g_browser_process->EndSession();
516 314
517 BrowserList::CloseAllBrowsers(); 315 CloseAllBrowsers();
518 316
519 // Send out notification. This is used during testing so that the test harness 317 // Send out notification. This is used during testing so that the test harness
520 // can properly shutdown before we exit. 318 // can properly shutdown before we exit.
521 content::NotificationService::current()->Notify( 319 content::NotificationService::current()->Notify(
522 chrome::NOTIFICATION_SESSION_END, 320 chrome::NOTIFICATION_SESSION_END,
523 content::NotificationService::AllSources(), 321 content::NotificationService::AllSources(),
524 content::NotificationService::NoDetails()); 322 content::NotificationService::NoDetails());
525 323
526 // This will end by terminating the process. 324 // This will end by terminating the process.
527 content::ImmediateShutdownAndExitProcess(); 325 content::ImmediateShutdownAndExitProcess();
528 } 326 }
529 327
530 // static 328 void StartKeepAlive() {
531 int BrowserList::keep_alive_count_ = 0;
532
533 // static
534 void BrowserList::StartKeepAlive() {
535 // Increment the browser process refcount as long as we're keeping the 329 // Increment the browser process refcount as long as we're keeping the
536 // application alive. 330 // application alive.
537 if (!WillKeepAlive()) 331 if (!WillKeepAlive())
538 g_browser_process->AddRefModule(); 332 g_browser_process->AddRefModule();
539 keep_alive_count_++; 333 ++g_keep_alive_count;
540 } 334 }
541 335
542 // static 336 void EndKeepAlive() {
543 void BrowserList::EndKeepAlive() { 337 DCHECK_GT(g_keep_alive_count, 0);
544 DCHECK_GT(keep_alive_count_, 0); 338 --g_keep_alive_count;
545 keep_alive_count_--;
546 339
547 DCHECK(g_browser_process); 340 DCHECK(g_browser_process);
548 // Although we should have a browser process, if there is none, 341 // Although we should have a browser process, if there is none,
549 // there is nothing to do. 342 // there is nothing to do.
550 if (!g_browser_process) return; 343 if (!g_browser_process) return;
551 344
552 // Allow the app to shutdown again. 345 // Allow the app to shutdown again.
553 if (!WillKeepAlive()) { 346 if (!WillKeepAlive()) {
554 g_browser_process->ReleaseModule(); 347 g_browser_process->ReleaseModule();
555 // If there are no browsers open and we aren't already shutting down, 348 // If there are no browsers open and we aren't already shutting down,
556 // initiate a shutdown. Also skips shutdown if this is a unit test 349 // initiate a shutdown. Also skips shutdown if this is a unit test
557 // (MessageLoop::current() == null). 350 // (MessageLoop::current() == null).
558 if (browsers().empty() && !browser_shutdown::IsTryingToQuit() && 351 if (BrowserList::empty() && !browser_shutdown::IsTryingToQuit() &&
559 MessageLoop::current()) 352 MessageLoop::current())
560 CloseAllBrowsers(); 353 CloseAllBrowsers();
561 } 354 }
562 } 355 }
563 356
564 // static 357 bool WillKeepAlive() {
565 bool BrowserList::WillKeepAlive() { 358 return g_keep_alive_count > 0;
566 return keep_alive_count_ > 0;
567 } 359 }
568 360
569 // static 361 } // namespace browser
570 BrowserList::const_iterator BrowserList::begin() {
571 return browsers().begin();
572 }
573
574 // static
575 BrowserList::const_iterator BrowserList::end() {
576 return browsers().end();
577 }
578
579 // static
580 bool BrowserList::empty() {
581 return browsers().empty();
582 }
583
584 // static
585 size_t BrowserList::size() {
586 return browsers().size();
587 }
588
589 // static
590 void BrowserList::SetLastActive(Browser* browser) {
591 // If the browser is currently trying to quit, we don't want to set the last
592 // active browser because that can alter the last active browser that the user
593 // intended depending on the order in which the windows close.
594 if (browser_shutdown::IsTryingToQuit())
595 return;
596 RemoveBrowserFrom(browser, &last_active_browsers());
597 last_active_browsers().push_back(browser);
598
599 FOR_EACH_OBSERVER(Observer, observers(), OnBrowserSetLastActive(browser));
600 }
601
602 // static
603 Browser* BrowserList::GetLastActive() {
604 if (!last_active_browsers().empty())
605 return *(last_active_browsers().rbegin());
606
607 return NULL;
608 }
609
610 // static
611 BrowserList::const_reverse_iterator BrowserList::begin_last_active() {
612 return last_active_browsers().rbegin();
613 }
614
615 // static
616 BrowserList::const_reverse_iterator BrowserList::end_last_active() {
617 return last_active_browsers().rend();
618 }
619
620 // static
621 bool BrowserList::IsOffTheRecordSessionActive() {
622 for (BrowserList::const_iterator i = BrowserList::begin();
623 i != BrowserList::end(); ++i) {
624 if ((*i)->profile()->IsOffTheRecord())
625 return true;
626 }
627 return false;
628 }
629
630 // static
631 bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile* profile) {
632 #if defined(OS_CHROMEOS)
633 // In ChromeOS, we assume that the default profile is always valid, so if
634 // we are in guest mode, keep the OTR profile active so it won't be deleted.
635 if (chromeos::UserManager::Get()->IsLoggedInAsGuest())
636 return true;
637 #endif
638 for (BrowserList::const_iterator i = BrowserList::begin();
639 i != BrowserList::end(); ++i) {
640 if ((*i)->profile()->IsSameProfile(profile) &&
641 (*i)->profile()->IsOffTheRecord()) {
642 return true;
643 }
644 }
645 return false;
646 }
647
648 // static
649 void BrowserList::RemoveBrowserFrom(Browser* browser,
650 BrowserVector* browser_list) {
651 const iterator remove_browser =
652 std::find(browser_list->begin(), browser_list->end(), browser);
653 if (remove_browser != browser_list->end())
654 browser_list->erase(remove_browser);
655 }
656
657 TabContentsIterator::TabContentsIterator()
658 : browser_iterator_(BrowserList::begin()),
659 web_view_index_(-1),
660 bg_printing_iterator_(GetBackgroundPrintingManager()->begin()),
661 cur_(NULL) {
662 Advance();
663 }
664
665 void TabContentsIterator::Advance() {
666 // The current WebContents should be valid unless we are at the beginning.
667 DCHECK(cur_ || (web_view_index_ == -1 &&
668 browser_iterator_ == BrowserList::begin()))
669 << "Trying to advance past the end";
670
671 // Update cur_ to the next WebContents in the list.
672 while (browser_iterator_ != BrowserList::end()) {
673 if (++web_view_index_ >= (*browser_iterator_)->tab_count()) {
674 // Advance to the next Browser in the list.
675 ++browser_iterator_;
676 web_view_index_ = -1;
677 continue;
678 }
679
680 TabContentsWrapper* next_tab =
681 (*browser_iterator_)->GetTabContentsWrapperAt(web_view_index_);
682 if (next_tab) {
683 cur_ = next_tab;
684 return;
685 }
686 }
687 // If no more WebContents from Browsers, check the BackgroundPrintingManager.
688 while (bg_printing_iterator_ != GetBackgroundPrintingManager()->end()) {
689 cur_ = *bg_printing_iterator_;
690 CHECK(cur_);
691 ++bg_printing_iterator_;
692 return;
693 }
694 // Reached the end - no more WebContents.
695 cur_ = NULL;
696 }
OLDNEW
« no previous file with comments | « chrome/browser/lifetime/application_lifetime.h ('k') | chrome/browser/lifetime/application_lifetime_aura.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698