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/browser_process_impl.h" | 5 #include "chrome/browser/browser_process_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <map> | 8 #include <map> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
| 11 #include "base/atomic_ref_count.h" |
11 #include "base/bind.h" | 12 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
13 #include "base/command_line.h" | 14 #include "base/command_line.h" |
14 #include "base/debug/alias.h" | 15 #include "base/debug/alias.h" |
15 #include "base/debug/leak_annotations.h" | 16 #include "base/debug/leak_annotations.h" |
16 #include "base/files/file_path.h" | 17 #include "base/files/file_path.h" |
17 #include "base/path_service.h" | 18 #include "base/path_service.h" |
18 #include "base/prefs/json_pref_store.h" | 19 #include "base/prefs/json_pref_store.h" |
19 #include "base/prefs/pref_registry_simple.h" | 20 #include "base/prefs/pref_registry_simple.h" |
20 #include "base/prefs/pref_service.h" | 21 #include "base/prefs/pref_service.h" |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 // Reset associated state right after actual thread is stopped, | 309 // Reset associated state right after actual thread is stopped, |
309 // as io_thread_.global_ cleanup happens in CleanUp on the IO | 310 // as io_thread_.global_ cleanup happens in CleanUp on the IO |
310 // thread, i.e. as the thread exits its message loop. | 311 // thread, i.e. as the thread exits its message loop. |
311 // | 312 // |
312 // This is important also because in various places, the | 313 // This is important also because in various places, the |
313 // IOThread object being NULL is considered synonymous with the | 314 // IOThread object being NULL is considered synonymous with the |
314 // IO thread having stopped. | 315 // IO thread having stopped. |
315 io_thread_.reset(); | 316 io_thread_.reset(); |
316 } | 317 } |
317 | 318 |
318 #if defined(USE_X11) || defined(OS_WIN) | |
319 static void Signal(base::WaitableEvent* event) { | |
320 event->Signal(); | |
321 } | |
322 #endif | |
323 | |
324 unsigned int BrowserProcessImpl::AddRefModule() { | 319 unsigned int BrowserProcessImpl::AddRefModule() { |
325 DCHECK(CalledOnValidThread()); | 320 DCHECK(CalledOnValidThread()); |
326 | 321 |
327 // CHECK(!IsShuttingDown()); | 322 // CHECK(!IsShuttingDown()); |
328 if (IsShuttingDown()) { | 323 if (IsShuttingDown()) { |
329 // Copy the stacktrace which released the final reference onto our stack so | 324 // Copy the stacktrace which released the final reference onto our stack so |
330 // it will be available in the crash report for inspection. | 325 // it will be available in the crash report for inspection. |
331 base::debug::StackTrace callstack = release_last_reference_callstack_; | 326 base::debug::StackTrace callstack = release_last_reference_callstack_; |
332 base::debug::Alias(&callstack); | 327 base::debug::Alias(&callstack); |
333 CHECK(false); | 328 CHECK(false); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 #if defined(OS_MACOSX) | 372 #if defined(OS_MACOSX) |
378 base::MessageLoop::current()->PostTask( | 373 base::MessageLoop::current()->PostTask( |
379 FROM_HERE, | 374 FROM_HERE, |
380 base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop)); | 375 base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop)); |
381 #endif | 376 #endif |
382 base::MessageLoop::current()->Quit(); | 377 base::MessageLoop::current()->Quit(); |
383 } | 378 } |
384 return module_ref_count_; | 379 return module_ref_count_; |
385 } | 380 } |
386 | 381 |
| 382 namespace { |
| 383 |
| 384 // Used at the end of session to block the UI thread for completion of sentinel |
| 385 // tasks on the set of threads used to persist profile data and local state. |
| 386 // This is done to ensure that the data has been persisted to disk before |
| 387 // continuing. |
| 388 class RundownTaskCounter : |
| 389 public base::RefCountedThreadSafe<RundownTaskCounter> { |
| 390 public: |
| 391 RundownTaskCounter(); |
| 392 |
| 393 // Posts a rundown task to |task_runner|, can be invoked an arbitrary number |
| 394 // of times before calling TimedWait. |
| 395 void Post(base::SequencedTaskRunner* task_runner); |
| 396 |
| 397 // Waits until the count is zero or |max_time| has passed. |
| 398 // This can only be called once per instance. |
| 399 bool TimedWait(const base::TimeDelta& max_time); |
| 400 |
| 401 private: |
| 402 friend class base::RefCountedThreadSafe<RundownTaskCounter>; |
| 403 ~RundownTaskCounter() {} |
| 404 |
| 405 // Decrements the counter and releases the waitable event on transition to |
| 406 // zero. |
| 407 void Decrement(); |
| 408 |
| 409 // The count starts at one to defer the possibility of one->zero transitions |
| 410 // until TimedWait is called. |
| 411 base::AtomicRefCount count_; |
| 412 base::WaitableEvent waitable_event_; |
| 413 |
| 414 DISALLOW_COPY_AND_ASSIGN(RundownTaskCounter); |
| 415 }; |
| 416 |
| 417 RundownTaskCounter::RundownTaskCounter() |
| 418 : count_(1), waitable_event_(true, false) { |
| 419 } |
| 420 |
| 421 void RundownTaskCounter::Post(base::SequencedTaskRunner* task_runner) { |
| 422 // As the count starts off at one, it should never get to zero unless |
| 423 // TimedWait has been called. |
| 424 DCHECK(!base::AtomicRefCountIsZero(&count_)); |
| 425 |
| 426 base::AtomicRefCountInc(&count_); |
| 427 |
| 428 task_runner->PostTask(FROM_HERE, |
| 429 base::Bind(&RundownTaskCounter::Decrement, this)); |
| 430 } |
| 431 |
| 432 void RundownTaskCounter::Decrement() { |
| 433 if (!base::AtomicRefCountDec(&count_)) |
| 434 waitable_event_.Signal(); |
| 435 } |
| 436 |
| 437 bool RundownTaskCounter::TimedWait(const base::TimeDelta& max_time) { |
| 438 // Decrement the excess count from the constructor. |
| 439 Decrement(); |
| 440 |
| 441 return waitable_event_.TimedWait(max_time); |
| 442 } |
| 443 |
| 444 } // namespace |
| 445 |
387 void BrowserProcessImpl::EndSession() { | 446 void BrowserProcessImpl::EndSession() { |
388 // Mark all the profiles as clean. | 447 // Mark all the profiles as clean. |
389 ProfileManager* pm = profile_manager(); | 448 ProfileManager* pm = profile_manager(); |
390 std::vector<Profile*> profiles(pm->GetLoadedProfiles()); | 449 std::vector<Profile*> profiles(pm->GetLoadedProfiles()); |
391 for (size_t i = 0; i < profiles.size(); ++i) | 450 scoped_refptr<RundownTaskCounter> rundown_counter(new RundownTaskCounter()); |
392 profiles[i]->SetExitType(Profile::EXIT_SESSION_ENDED); | 451 for (size_t i = 0; i < profiles.size(); ++i) { |
| 452 Profile* profile = profiles[i]; |
| 453 profile->SetExitType(Profile::EXIT_SESSION_ENDED); |
| 454 |
| 455 rundown_counter->Post(profile->GetIOTaskRunner()); |
| 456 } |
393 | 457 |
394 // Tell the metrics service it was cleanly shutdown. | 458 // Tell the metrics service it was cleanly shutdown. |
395 MetricsService* metrics = g_browser_process->metrics_service(); | 459 MetricsService* metrics = g_browser_process->metrics_service(); |
396 if (metrics && local_state()) { | 460 if (metrics && local_state()) { |
397 metrics->RecordStartOfSessionEnd(); | 461 metrics->RecordStartOfSessionEnd(); |
398 #if !defined(OS_CHROMEOS) | 462 #if !defined(OS_CHROMEOS) |
399 // MetricsService lazily writes to prefs, force it to write now. | 463 // MetricsService lazily writes to prefs, force it to write now. |
400 // On ChromeOS, chrome gets killed when hangs, so no need to | 464 // On ChromeOS, chrome gets killed when hangs, so no need to |
401 // commit metrics::prefs::kStabilitySessionEndCompleted change immediately. | 465 // commit metrics::prefs::kStabilitySessionEndCompleted change immediately. |
402 local_state()->CommitPendingWrite(); | 466 local_state()->CommitPendingWrite(); |
| 467 |
| 468 rundown_counter->Post(local_state_task_runner_); |
403 #endif | 469 #endif |
404 } | 470 } |
405 | 471 |
406 // http://crbug.com/125207 | 472 // http://crbug.com/125207 |
407 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 473 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
408 | 474 |
409 // We must write that the profile and metrics service shutdown cleanly, | 475 // We must write that the profile and metrics service shutdown cleanly, |
410 // otherwise on startup we'll think we crashed. So we block until done and | 476 // otherwise on startup we'll think we crashed. So we block until done and |
411 // then proceed with normal shutdown. | 477 // then proceed with normal shutdown. |
412 #if defined(USE_X11) || defined(OS_WIN) | 478 #if defined(USE_X11) || defined(OS_WIN) |
413 // Create a waitable event to block on file writing being complete. | 479 // Do a best-effort wait on the successful countdown of rundown tasks. Note |
| 480 // that if we don't complete "quickly enough", Windows will terminate our |
| 481 // process. |
414 // | 482 // |
415 // On Windows, we previously posted a message to FILE and then ran a nested | 483 // On Windows, we previously posted a message to FILE and then ran a nested |
416 // message loop, waiting for that message to be processed until quitting. | 484 // message loop, waiting for that message to be processed until quitting. |
417 // However, doing so means that other messages will also be processed. In | 485 // However, doing so means that other messages will also be processed. In |
418 // particular, if the GPU process host notices that the GPU has been killed | 486 // particular, if the GPU process host notices that the GPU has been killed |
419 // during shutdown, it races exiting the nested loop with the process host | 487 // during shutdown, it races exiting the nested loop with the process host |
420 // blocking the message loop attempting to re-establish a connection to the | 488 // blocking the message loop attempting to re-establish a connection to the |
421 // GPU process synchronously. Because the system may not be allowing | 489 // GPU process synchronously. Because the system may not be allowing |
422 // processes to launch, this can result in a hang. See | 490 // processes to launch, this can result in a hang. See |
423 // http://crbug.com/318527. | 491 // http://crbug.com/318527. |
424 scoped_ptr<base::WaitableEvent> done_writing( | 492 rundown_counter->TimedWait( |
425 new base::WaitableEvent(false, false)); | 493 base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds)); |
426 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
427 base::Bind(Signal, done_writing.get())); | |
428 // If all file writes haven't cleared in the timeout, leak the WaitableEvent | |
429 // so that there's no race to reference it in Signal(). | |
430 if (!done_writing->TimedWait( | |
431 base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds))) { | |
432 ignore_result(done_writing.release()); | |
433 } | |
434 #else | 494 #else |
435 NOTIMPLEMENTED(); | 495 NOTIMPLEMENTED(); |
436 #endif | 496 #endif |
437 } | 497 } |
438 | 498 |
439 MetricsServicesManager* BrowserProcessImpl::GetMetricsServicesManager() { | 499 MetricsServicesManager* BrowserProcessImpl::GetMetricsServicesManager() { |
440 DCHECK(CalledOnValidThread()); | 500 DCHECK(CalledOnValidThread()); |
441 if (!metrics_services_manager_) | 501 if (!metrics_services_manager_) |
442 metrics_services_manager_.reset(new MetricsServicesManager(local_state())); | 502 metrics_services_manager_.reset(new MetricsServicesManager(local_state())); |
443 return metrics_services_manager_.get(); | 503 return metrics_services_manager_.get(); |
(...skipping 664 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1108 } | 1168 } |
1109 | 1169 |
1110 void BrowserProcessImpl::OnAutoupdateTimer() { | 1170 void BrowserProcessImpl::OnAutoupdateTimer() { |
1111 if (CanAutorestartForUpdate()) { | 1171 if (CanAutorestartForUpdate()) { |
1112 DLOG(WARNING) << "Detected update. Restarting browser."; | 1172 DLOG(WARNING) << "Detected update. Restarting browser."; |
1113 RestartBackgroundInstance(); | 1173 RestartBackgroundInstance(); |
1114 } | 1174 } |
1115 } | 1175 } |
1116 | 1176 |
1117 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) | 1177 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) |
OLD | NEW |