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" | 7 #include "base/command_line.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop.h" | |
10 #include "base/metrics/histogram.h" | 9 #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/lifetime/application_lifetime.h" |
15 #include "chrome/browser/metrics/thread_watcher.h" | |
16 #include "chrome/browser/prefs/pref_service.h" | 14 #include "chrome/browser/prefs/pref_service.h" |
17 #include "chrome/browser/printing/background_printing_manager.h" | 15 #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" | |
20 #include "chrome/browser/ui/browser.h" | 17 #include "chrome/browser/ui/browser.h" |
21 #include "chrome/browser/ui/browser_window.h" | 18 #include "chrome/browser/ui/browser_window.h" |
22 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 19 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
23 #include "chrome/common/chrome_notification_types.h" | 20 #include "chrome/common/chrome_notification_types.h" |
24 #include "chrome/common/chrome_switches.h" | 21 #include "chrome/common/chrome_switches.h" |
25 #include "chrome/common/pref_names.h" | 22 #include "chrome/common/pref_names.h" |
26 #include "content/public/browser/browser_shutdown.h" | 23 #include "content/public/browser/browser_shutdown.h" |
27 #include "content/public/browser/browser_thread.h" | 24 #include "content/public/browser/browser_thread.h" |
28 #include "content/public/browser/navigation_details.h" | 25 #include "content/public/browser/navigation_details.h" |
29 #include "content/public/browser/notification_registrar.h" | 26 #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" | 28 #include "content/public/browser/render_process_host.h" |
32 #include "content/public/common/result_codes.h" | 29 #include "content/public/common/result_codes.h" |
33 | 30 |
34 #if defined(OS_MACOSX) | |
35 #include "chrome/browser/chrome_browser_application_mac.h" | |
36 #endif | |
37 | |
38 #if defined(OS_CHROMEOS) | 31 #if defined(OS_CHROMEOS) |
39 #include "base/chromeos/chromeos_version.h" | |
40 #include "chrome/browser/chromeos/boot_times_loader.h" | |
41 #include "chrome/browser/chromeos/login/user_manager.h" | 32 #include "chrome/browser/chromeos/login/user_manager.h" |
42 #include "chromeos/dbus/dbus_thread_manager.h" | |
43 #include "chromeos/dbus/session_manager_client.h" | |
44 #include "chromeos/dbus/update_engine_client.h" | |
45 #endif | 33 #endif |
46 | 34 |
47 using content::WebContents; | 35 using content::WebContents; |
48 | 36 |
49 namespace { | 37 namespace { |
50 | 38 |
51 // This object is instantiated when the first Browser object is added to the | 39 // 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 | 40 // list and delete when the last one is removed. It watches for loads and |
53 // creates histograms of some global object counts. | 41 // creates histograms of some global object counts. |
54 class BrowserActivityObserver : public content::NotificationObserver { | 42 class BrowserActivityObserver : public content::NotificationObserver { |
55 public: | 43 public: |
56 BrowserActivityObserver() { | 44 BrowserActivityObserver() { |
57 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | 45 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
58 content::NotificationService::AllSources()); | 46 content::NotificationService::AllSources()); |
| 47 registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING, |
| 48 content::NotificationService::AllSources()); |
59 } | 49 } |
60 ~BrowserActivityObserver() {} | 50 ~BrowserActivityObserver() {} |
61 | 51 |
62 private: | 52 private: |
63 // content::NotificationObserver implementation. | 53 // content::NotificationObserver implementation. |
64 virtual void Observe(int type, | 54 virtual void Observe(int type, |
65 const content::NotificationSource& source, | 55 const content::NotificationSource& source, |
66 const content::NotificationDetails& details) { | 56 const content::NotificationDetails& details) { |
67 DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED); | 57 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { |
68 const content::LoadCommittedDetails& load = | 58 const content::LoadCommittedDetails& load = |
69 *content::Details<content::LoadCommittedDetails>(details).ptr(); | 59 *content::Details<content::LoadCommittedDetails>(details).ptr(); |
70 if (!load.is_navigation_to_different_page()) | 60 if (!load.is_navigation_to_different_page()) |
71 return; // Don't log for subframes or other trivial types. | 61 return; // Don't log for subframes or other trivial types. |
72 | 62 |
73 LogRenderProcessHostCount(); | 63 LogRenderProcessHostCount(); |
74 LogBrowserTabCount(); | 64 LogBrowserTabCount(); |
| 65 } else if (type == content::NOTIFICATION_APP_TERMINATING) { |
| 66 delete this; |
| 67 } |
75 } | 68 } |
76 | 69 |
77 // Counts the number of active RenderProcessHosts and logs them. | 70 // Counts the number of active RenderProcessHosts and logs them. |
78 void LogRenderProcessHostCount() const { | 71 void LogRenderProcessHostCount() const { |
79 int hosts_count = 0; | 72 int hosts_count = 0; |
80 for (content::RenderProcessHost::iterator i( | 73 for (content::RenderProcessHost::iterator i( |
81 content::RenderProcessHost::AllHostsIterator()); | 74 content::RenderProcessHost::AllHostsIterator()); |
82 !i.IsAtEnd(); i.Advance()) | 75 !i.IsAtEnd(); i.Advance()) |
83 ++hosts_count; | 76 ++hosts_count; |
84 UMA_HISTOGRAM_CUSTOM_COUNTS("MPArch.RPHCountPerLoad", hosts_count, | 77 UMA_HISTOGRAM_CUSTOM_COUNTS("MPArch.RPHCountPerLoad", hosts_count, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 static ObserverList<BrowserList::Observer>& observers() { | 122 static ObserverList<BrowserList::Observer>& observers() { |
130 CR_DEFINE_STATIC_LOCAL( | 123 CR_DEFINE_STATIC_LOCAL( |
131 ObserverList<BrowserList::Observer>, observer_vector, ()); | 124 ObserverList<BrowserList::Observer>, observer_vector, ()); |
132 return observer_vector; | 125 return observer_vector; |
133 } | 126 } |
134 | 127 |
135 printing::BackgroundPrintingManager* GetBackgroundPrintingManager() { | 128 printing::BackgroundPrintingManager* GetBackgroundPrintingManager() { |
136 return g_browser_process->background_printing_manager(); | 129 return g_browser_process->background_printing_manager(); |
137 } | 130 } |
138 | 131 |
139 // 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 | |
141 // handle unload handler. | |
142 bool AreAllBrowsersCloseable() { | |
143 BrowserList::const_iterator browser_it = BrowserList::begin(); | |
144 if (browser_it == BrowserList::end()) | |
145 return true; | |
146 | |
147 // If there are any downloads active, all browsers are not closeable. | |
148 if (DownloadService::DownloadCountAllProfiles() > 0) | |
149 return false; | |
150 | |
151 // Check TabsNeedBeforeUnloadFired(). | |
152 for (; browser_it != BrowserList::end(); ++browser_it) { | |
153 if ((*browser_it)->TabsNeedBeforeUnloadFired()) | |
154 return false; | |
155 } | |
156 return true; | |
157 } | |
158 | |
159 // Emits APP_TERMINATING notification. It is guaranteed that the | |
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 | |
172 #if defined(OS_CHROMEOS) | |
173 // Whether a session manager requested to shutdown. | |
174 bool g_session_manager_requested_shutdown = true; | |
175 #endif | |
176 | |
177 } // namespace | 132 } // namespace |
178 | 133 |
179 // static | 134 // static |
180 void BrowserList::AddBrowser(Browser* browser) { | 135 void BrowserList::AddBrowser(Browser* browser) { |
181 DCHECK(browser); | 136 DCHECK(browser); |
182 browsers().push_back(browser); | 137 browsers().push_back(browser); |
183 | 138 |
184 g_browser_process->AddRefModule(); | 139 g_browser_process->AddRefModule(); |
185 | 140 |
186 if (!activity_observer) | 141 if (!activity_observer) |
187 activity_observer = new BrowserActivityObserver; | 142 activity_observer = new BrowserActivityObserver; |
188 | 143 |
189 content::NotificationService::current()->Notify( | 144 content::NotificationService::current()->Notify( |
190 chrome::NOTIFICATION_BROWSER_OPENED, | 145 chrome::NOTIFICATION_BROWSER_OPENED, |
191 content::Source<Browser>(browser), | 146 content::Source<Browser>(browser), |
192 content::NotificationService::NoDetails()); | 147 content::NotificationService::NoDetails()); |
193 | 148 |
194 // Send out notifications after add has occurred. Do some basic checking to | 149 // 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. | 150 // try to catch evil observers that change the list from under us. |
196 size_t original_count = observers().size(); | 151 size_t original_count = observers().size(); |
197 FOR_EACH_OBSERVER(Observer, observers(), OnBrowserAdded(browser)); | 152 FOR_EACH_OBSERVER(Observer, observers(), OnBrowserAdded(browser)); |
198 DCHECK_EQ(original_count, observers().size()) | 153 DCHECK_EQ(original_count, observers().size()) |
199 << "observer list modified during notification"; | 154 << "observer list modified during notification"; |
200 } | 155 } |
201 | 156 |
202 // static | 157 // static |
203 void BrowserList::MarkAsCleanShutdown() { | |
204 for (const_iterator i = begin(); i != end(); ++i) { | |
205 (*i)->profile()->MarkAsCleanShutdown(); | |
206 } | |
207 } | |
208 | |
209 void BrowserList::AttemptExitInternal() { | |
210 content::NotificationService::current()->Notify( | |
211 content::NOTIFICATION_APP_EXITING, | |
212 content::NotificationService::AllSources(), | |
213 content::NotificationService::NoDetails()); | |
214 | |
215 #if !defined(OS_MACOSX) | |
216 // On most platforms, closing all windows causes the application to exit. | |
217 CloseAllBrowsers(); | |
218 #else | |
219 // 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) | |
221 // that is done, will cause the application to exit cleanly. | |
222 chrome_browser_application_mac::Terminate(); | |
223 #endif | |
224 } | |
225 | |
226 // static | |
227 void BrowserList::NotifyAndTerminate(bool fast_path) { | |
228 #if defined(OS_CHROMEOS) | |
229 static bool notified = false; | |
230 // Don't ask SessionManager to shutdown if | |
231 // a) a shutdown request has already been sent. | |
232 // b) shutdown request comes from session manager. | |
233 if (notified || g_session_manager_requested_shutdown) | |
234 return; | |
235 notified = true; | |
236 #endif | |
237 | |
238 if (fast_path) | |
239 NotifyAppTerminating(); | |
240 | |
241 #if defined(OS_CHROMEOS) | |
242 if (base::chromeos::IsRunningOnChromeOS()) { | |
243 // If we're on a ChromeOS device, reboot if an update has been applied, | |
244 // or else signal the session manager to log out. | |
245 chromeos::UpdateEngineClient* update_engine_client | |
246 = chromeos::DBusThreadManager::Get()->GetUpdateEngineClient(); | |
247 if (update_engine_client->GetLastStatus().status == | |
248 chromeos::UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) { | |
249 update_engine_client->RebootAfterUpdate(); | |
250 } else { | |
251 chromeos::DBusThreadManager::Get()->GetSessionManagerClient() | |
252 ->StopSession(); | |
253 } | |
254 } else { | |
255 // If running the Chrome OS build, but we're not on the device, act | |
256 // as if we received signal from SessionManager. | |
257 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | |
258 base::Bind(&BrowserList::ExitCleanly)); | |
259 } | |
260 #endif | |
261 } | |
262 | |
263 void BrowserList::OnAppExiting() { | |
264 static bool notified = false; | |
265 if (notified) | |
266 return; | |
267 notified = true; | |
268 | |
269 delete activity_observer; | |
270 activity_observer = NULL; | |
271 HandleAppExitingForPlatform(); | |
272 } | |
273 | |
274 // static | |
275 void BrowserList::RemoveBrowser(Browser* browser) { | 158 void BrowserList::RemoveBrowser(Browser* browser) { |
276 RemoveBrowserFrom(browser, &last_active_browsers()); | 159 RemoveBrowserFrom(browser, &last_active_browsers()); |
277 | 160 |
278 // Many UI tests rely on closing the last browser window quitting the | 161 // Many UI tests rely on closing the last browser window quitting the |
279 // application. | 162 // application. |
280 // Mac: Closing all windows does not indicate quitting the application. Lie | 163 // Mac: Closing all windows does not indicate quitting the application. Lie |
281 // for now and ignore behavior outside of unit tests. | 164 // for now and ignore behavior outside of unit tests. |
282 // ChromeOS: Force closing last window to close app with flag. | 165 // ChromeOS: Force closing last window to close app with flag. |
283 // TODO(andybons | pkotwicz): Fix the UI tests to Do The Right Thing. | 166 // TODO(andybons | pkotwicz): Fix the UI tests to Do The Right Thing. |
284 #if defined(OS_CHROMEOS) | 167 #if defined(OS_CHROMEOS) |
(...skipping 27 matching lines...) Expand all Loading... |
312 // If we're exiting, send out the APP_TERMINATING notification to allow other | 195 // If we're exiting, send out the APP_TERMINATING notification to allow other |
313 // modules to shut themselves down. | 196 // modules to shut themselves down. |
314 if (browsers().empty() && | 197 if (browsers().empty() && |
315 (browser_shutdown::IsTryingToQuit() || | 198 (browser_shutdown::IsTryingToQuit() || |
316 g_browser_process->IsShuttingDown())) { | 199 g_browser_process->IsShuttingDown())) { |
317 // Last browser has just closed, and this is a user-initiated quit or there | 200 // 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 | 201 // is no module keeping the app alive, so send out our notification. No need |
319 // to call ProfileManager::ShutdownSessionServices() as part of the | 202 // to call ProfileManager::ShutdownSessionServices() as part of the |
320 // shutdown, because Browser::WindowClosing() already makes sure that the | 203 // shutdown, because Browser::WindowClosing() already makes sure that the |
321 // SessionService is created and notified. | 204 // SessionService is created and notified. |
322 NotifyAppTerminating(); | 205 browser::NotifyAppTerminating(); |
323 OnAppExiting(); | 206 browser::OnAppExiting(); |
324 } | 207 } |
325 } | 208 } |
326 | 209 |
327 // static | 210 // static |
328 void BrowserList::AddObserver(BrowserList::Observer* observer) { | 211 void BrowserList::AddObserver(BrowserList::Observer* observer) { |
329 observers().AddObserver(observer); | 212 observers().AddObserver(observer); |
330 } | 213 } |
331 | 214 |
332 // static | 215 // static |
333 void BrowserList::RemoveObserver(BrowserList::Observer* observer) { | 216 void BrowserList::RemoveObserver(BrowserList::Observer* observer) { |
334 observers().RemoveObserver(observer); | 217 observers().RemoveObserver(observer); |
335 } | 218 } |
336 | 219 |
337 // static | |
338 void BrowserList::CloseAllBrowsers() { | |
339 bool session_ending = | |
340 browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION; | |
341 // Tell everyone that we are shutting down. | |
342 browser_shutdown::SetTryingToQuit(true); | |
343 | |
344 // Before we close the browsers shutdown all session services. That way an | |
345 // exit can restore all browsers open before exiting. | |
346 ProfileManager::ShutdownSessionServices(); | |
347 | |
348 // 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. | |
350 if (browser_shutdown::ShuttingDownWithoutClosingBrowsers() || | |
351 browsers().empty()) { | |
352 NotifyAndTerminate(true); | |
353 OnAppExiting(); | |
354 return; | |
355 } | |
356 | |
357 #if defined(OS_CHROMEOS) | |
358 chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker( | |
359 "StartedClosingWindows", false); | |
360 #endif | |
361 for (BrowserList::const_iterator i = BrowserList::begin(); | |
362 i != BrowserList::end();) { | |
363 Browser* browser = *i; | |
364 browser->window()->Close(); | |
365 if (!session_ending) { | |
366 ++i; | |
367 } else { | |
368 // This path is hit during logoff/power-down. In this case we won't get | |
369 // a final message and so we force the browser to be deleted. | |
370 // Close doesn't immediately destroy the browser | |
371 // (Browser::TabStripEmpty() uses invoke later) but when we're ending the | |
372 // session we need to make sure the browser is destroyed now. So, invoke | |
373 // DestroyBrowser to make sure the browser is deleted and cleanup can | |
374 // happen. | |
375 while (browser->tab_count()) | |
376 delete browser->GetTabContentsWrapperAt(0); | |
377 browser->window()->DestroyBrowser(); | |
378 i = BrowserList::begin(); | |
379 if (i != BrowserList::end() && browser == *i) { | |
380 // Destroying the browser should have removed it from the browser list. | |
381 // We should never get here. | |
382 NOTREACHED(); | |
383 return; | |
384 } | |
385 } | |
386 } | |
387 } | |
388 | |
389 void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) { | 220 void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) { |
390 BrowserVector browsers_to_close; | 221 BrowserVector browsers_to_close; |
391 for (BrowserList::const_iterator i = BrowserList::begin(); | 222 for (BrowserList::const_iterator i = BrowserList::begin(); |
392 i != BrowserList::end(); ++i) { | 223 i != BrowserList::end(); ++i) { |
393 if ((*i)->profile()->GetOriginalProfile() == profile->GetOriginalProfile()) | 224 if ((*i)->profile()->GetOriginalProfile() == profile->GetOriginalProfile()) |
394 browsers_to_close.push_back(*i); | 225 browsers_to_close.push_back(*i); |
395 } | 226 } |
396 | 227 |
397 for (BrowserVector::const_iterator i = browsers_to_close.begin(); | 228 for (BrowserVector::const_iterator i = browsers_to_close.begin(); |
398 i != browsers_to_close.end(); ++i) { | 229 i != browsers_to_close.end(); ++i) { |
399 (*i)->window()->Close(); | 230 (*i)->window()->Close(); |
400 } | 231 } |
401 } | 232 } |
402 | 233 |
403 // static | 234 // static |
404 void BrowserList::AttemptUserExit() { | |
405 #if defined(OS_CHROMEOS) | |
406 chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutStarted", false); | |
407 // Write /tmp/uptime-logout-started as well. | |
408 const char kLogoutStarted[] = "logout-started"; | |
409 chromeos::BootTimesLoader::Get()->RecordCurrentStats(kLogoutStarted); | |
410 | |
411 // Login screen should show up in owner's locale. | |
412 PrefService* state = g_browser_process->local_state(); | |
413 if (state) { | |
414 std::string owner_locale = state->GetString(prefs::kOwnerLocale); | |
415 if (!owner_locale.empty() && | |
416 state->GetString(prefs::kApplicationLocale) != owner_locale && | |
417 !state->IsManagedPreference(prefs::kApplicationLocale)) { | |
418 state->SetString(prefs::kApplicationLocale, owner_locale); | |
419 state->CommitPendingWrite(); | |
420 } | |
421 } | |
422 g_session_manager_requested_shutdown = false; | |
423 // On ChromeOS, always terminate the browser, regardless of the result of | |
424 // AreAllBrowsersCloseable(). See crbug.com/123107. | |
425 BrowserList::NotifyAndTerminate(true); | |
426 #else | |
427 // Reset the restart bit that might have been set in cancelled restart | |
428 // request. | |
429 PrefService* pref_service = g_browser_process->local_state(); | |
430 pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, false); | |
431 AttemptExitInternal(); | |
432 #endif | |
433 } | |
434 | |
435 // static | |
436 void BrowserList::AttemptRestart() { | |
437 if (!CommandLine::ForCurrentProcess()->HasSwitch( | |
438 switches::kDisableRestoreSessionState)) { | |
439 BrowserVector::const_iterator it; | |
440 for (it = begin(); it != end(); ++it) | |
441 content::BrowserContext::SaveSessionState((*it)->profile()); | |
442 } | |
443 | |
444 PrefService* pref_service = g_browser_process->local_state(); | |
445 pref_service->SetBoolean(prefs::kWasRestarted, true); | |
446 | |
447 #if defined(OS_CHROMEOS) | |
448 // 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. | |
450 // Same session restore behavior happens in case of full restart after update. | |
451 AttemptUserExit(); | |
452 #else | |
453 // Set the flag to restore state after the restart. | |
454 pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true); | |
455 AttemptExit(); | |
456 #endif | |
457 } | |
458 | |
459 // static | |
460 void BrowserList::AttemptExit() { | |
461 // If we know that all browsers can be closed without blocking, | |
462 // don't notify users of crashes beyond this point. | |
463 // Note that MarkAsCleanShutdown does not set UMA's exit cleanly bit | |
464 // so crashes during shutdown are still reported in UMA. | |
465 if (AreAllBrowsersCloseable()) | |
466 MarkAsCleanShutdown(); | |
467 AttemptExitInternal(); | |
468 } | |
469 | |
470 #if defined(OS_CHROMEOS) | |
471 // A function called when SIGTERM is received. | |
472 // static | |
473 void BrowserList::ExitCleanly() { | |
474 // We always mark exit cleanly because SessionManager may kill | |
475 // chrome in 3 seconds after SIGTERM. | |
476 g_browser_process->EndSession(); | |
477 | |
478 // Don't block when SIGTERM is received. AreaAllBrowsersCloseable() | |
479 // can be false in following cases. a) power-off b) signout from | |
480 // screen locker. | |
481 if (!AreAllBrowsersCloseable()) | |
482 browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION); | |
483 AttemptExitInternal(); | |
484 } | |
485 #endif | |
486 | |
487 // static | |
488 void BrowserList::SessionEnding() { | |
489 // 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 | |
491 // process within a hang timeout to avoid user prompts. | |
492 | |
493 // 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 | |
495 // exit this function. | |
496 ShutdownWatcherHelper shutdown_watcher; | |
497 shutdown_watcher.Arm(base::TimeDelta::FromSeconds(90)); | |
498 | |
499 // EndSession is invoked once per frame. Only do something the first time. | |
500 static bool already_ended = false; | |
501 // We may get called in the middle of shutdown, e.g. http://crbug.com/70852 | |
502 // In this case, do nothing. | |
503 if (already_ended || !content::NotificationService::current()) | |
504 return; | |
505 already_ended = true; | |
506 | |
507 browser_shutdown::OnShutdownStarting(browser_shutdown::END_SESSION); | |
508 | |
509 content::NotificationService::current()->Notify( | |
510 content::NOTIFICATION_APP_EXITING, | |
511 content::NotificationService::AllSources(), | |
512 content::NotificationService::NoDetails()); | |
513 | |
514 // Write important data first. | |
515 g_browser_process->EndSession(); | |
516 | |
517 BrowserList::CloseAllBrowsers(); | |
518 | |
519 // Send out notification. This is used during testing so that the test harness | |
520 // can properly shutdown before we exit. | |
521 content::NotificationService::current()->Notify( | |
522 chrome::NOTIFICATION_SESSION_END, | |
523 content::NotificationService::AllSources(), | |
524 content::NotificationService::NoDetails()); | |
525 | |
526 // This will end by terminating the process. | |
527 content::ImmediateShutdownAndExitProcess(); | |
528 } | |
529 | |
530 // static | |
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 | |
536 // application alive. | |
537 if (!WillKeepAlive()) | |
538 g_browser_process->AddRefModule(); | |
539 keep_alive_count_++; | |
540 } | |
541 | |
542 // static | |
543 void BrowserList::EndKeepAlive() { | |
544 DCHECK_GT(keep_alive_count_, 0); | |
545 keep_alive_count_--; | |
546 | |
547 DCHECK(g_browser_process); | |
548 // Although we should have a browser process, if there is none, | |
549 // there is nothing to do. | |
550 if (!g_browser_process) return; | |
551 | |
552 // Allow the app to shutdown again. | |
553 if (!WillKeepAlive()) { | |
554 g_browser_process->ReleaseModule(); | |
555 // 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 | |
557 // (MessageLoop::current() == null). | |
558 if (browsers().empty() && !browser_shutdown::IsTryingToQuit() && | |
559 MessageLoop::current()) | |
560 CloseAllBrowsers(); | |
561 } | |
562 } | |
563 | |
564 // static | |
565 bool BrowserList::WillKeepAlive() { | |
566 return keep_alive_count_ > 0; | |
567 } | |
568 | |
569 // static | |
570 BrowserList::const_iterator BrowserList::begin() { | 235 BrowserList::const_iterator BrowserList::begin() { |
571 return browsers().begin(); | 236 return browsers().begin(); |
572 } | 237 } |
573 | 238 |
574 // static | 239 // static |
575 BrowserList::const_iterator BrowserList::end() { | 240 BrowserList::const_iterator BrowserList::end() { |
576 return browsers().end(); | 241 return browsers().end(); |
577 } | 242 } |
578 | 243 |
579 // static | 244 // static |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
687 // If no more WebContents from Browsers, check the BackgroundPrintingManager. | 352 // If no more WebContents from Browsers, check the BackgroundPrintingManager. |
688 while (bg_printing_iterator_ != GetBackgroundPrintingManager()->end()) { | 353 while (bg_printing_iterator_ != GetBackgroundPrintingManager()->end()) { |
689 cur_ = *bg_printing_iterator_; | 354 cur_ = *bg_printing_iterator_; |
690 CHECK(cur_); | 355 CHECK(cur_); |
691 ++bg_printing_iterator_; | 356 ++bg_printing_iterator_; |
692 return; | 357 return; |
693 } | 358 } |
694 // Reached the end - no more WebContents. | 359 // Reached the end - no more WebContents. |
695 cur_ = NULL; | 360 cur_ = NULL; |
696 } | 361 } |
OLD | NEW |