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/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 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 303 // Reset associated state right after actual thread is stopped, | 304 // Reset associated state right after actual thread is stopped, |
| 304 // as io_thread_.global_ cleanup happens in CleanUp on the IO | 305 // as io_thread_.global_ cleanup happens in CleanUp on the IO |
| 305 // thread, i.e. as the thread exits its message loop. | 306 // thread, i.e. as the thread exits its message loop. |
| 306 // | 307 // |
| 307 // This is important also because in various places, the | 308 // This is important also because in various places, the |
| 308 // IOThread object being NULL is considered synonymous with the | 309 // IOThread object being NULL is considered synonymous with the |
| 309 // IO thread having stopped. | 310 // IO thread having stopped. |
| 310 io_thread_.reset(); | 311 io_thread_.reset(); |
| 311 } | 312 } |
| 312 | 313 |
| 313 #if defined(USE_X11) || defined(OS_WIN) | |
| 314 static void Signal(base::WaitableEvent* event) { | |
| 315 event->Signal(); | |
| 316 } | |
| 317 #endif | |
| 318 | |
| 319 unsigned int BrowserProcessImpl::AddRefModule() { | 314 unsigned int BrowserProcessImpl::AddRefModule() { |
| 320 DCHECK(CalledOnValidThread()); | 315 DCHECK(CalledOnValidThread()); |
| 321 | 316 |
| 322 // CHECK(!IsShuttingDown()); | 317 // CHECK(!IsShuttingDown()); |
| 323 if (IsShuttingDown()) { | 318 if (IsShuttingDown()) { |
| 324 // Copy the stacktrace which released the final reference onto our stack so | 319 // Copy the stacktrace which released the final reference onto our stack so |
| 325 // it will be available in the crash report for inspection. | 320 // it will be available in the crash report for inspection. |
| 326 base::debug::StackTrace callstack = release_last_reference_callstack_; | 321 base::debug::StackTrace callstack = release_last_reference_callstack_; |
| 327 base::debug::Alias(&callstack); | 322 base::debug::Alias(&callstack); |
| 328 CHECK(false); | 323 CHECK(false); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 372 #if defined(OS_MACOSX) | 367 #if defined(OS_MACOSX) |
| 373 base::MessageLoop::current()->PostTask( | 368 base::MessageLoop::current()->PostTask( |
| 374 FROM_HERE, | 369 FROM_HERE, |
| 375 base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop)); | 370 base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop)); |
| 376 #endif | 371 #endif |
| 377 base::MessageLoop::current()->Quit(); | 372 base::MessageLoop::current()->Quit(); |
| 378 } | 373 } |
| 379 return module_ref_count_; | 374 return module_ref_count_; |
| 380 } | 375 } |
| 381 | 376 |
| 377 namespace { | |
| 378 | |
| 379 class RundownTaskCounter : | |
|
gab
2014/06/25 14:21:50
Add a meta-comment explaining the general purpose
Sigurður Ásgeirsson
2014/06/25 15:05:02
Done.
| |
| 380 public base::RefCountedThreadSafe<RundownTaskCounter> { | |
| 381 public: | |
| 382 RundownTaskCounter(); | |
| 383 | |
| 384 // Posts a rundown task to |task_runner|, can be invoked an arbitrary number | |
| 385 // of times before calling TimedWait. | |
| 386 void Post(base::SequencedTaskRunner* task_runner); | |
| 387 | |
| 388 // Waits until the count is zero or |max_time| has passed. | |
| 389 // This can only be called once per instance. | |
| 390 bool TimedWait(const base::TimeDelta& max_time); | |
| 391 | |
| 392 private: | |
| 393 friend class base::RefCountedThreadSafe<RundownTaskCounter>; | |
| 394 ~RundownTaskCounter() {} | |
| 395 | |
| 396 // Decrements the counter and releases the waitable | |
| 397 // event on transition to zero. | |
|
gab
2014/06/25 14:21:50
Some of this second line fits on the previous line
Sigurður Ásgeirsson
2014/06/25 15:05:02
Done.
| |
| 398 void Decrement(); | |
| 399 | |
| 400 // The count starts at one to defer the possibility of one->zero transitions | |
| 401 // until TimedWait is called. | |
| 402 base::AtomicRefCount count_; | |
| 403 base::WaitableEvent waitable_event_; | |
| 404 | |
| 405 DISALLOW_COPY_AND_ASSIGN(RundownTaskCounter); | |
| 406 }; | |
| 407 | |
| 408 RundownTaskCounter::RundownTaskCounter() | |
| 409 : count_(1), waitable_event_(true, false) { | |
| 410 } | |
| 411 | |
| 412 void RundownTaskCounter::Post(base::SequencedTaskRunner* task_runner) { | |
| 413 // As the count starts off at one, it should never get to zero unless | |
| 414 // TimedWait has been called. | |
| 415 DCHECK(!base::AtomicRefCountIsZero(&count_)); | |
| 416 | |
| 417 base::AtomicRefCountInc(&count_); | |
| 418 | |
| 419 task_runner->PostTask(FROM_HERE, | |
| 420 base::Bind(&RundownTaskCounter::Decrement, this)); | |
| 421 } | |
| 422 | |
| 423 void RundownTaskCounter::Decrement() { | |
| 424 if (!base::AtomicRefCountDec(&count_)) | |
| 425 waitable_event_.Signal(); | |
| 426 } | |
| 427 | |
| 428 bool RundownTaskCounter::TimedWait(const base::TimeDelta& max_time) { | |
| 429 // Decrement the excess count from the constructor. | |
| 430 Decrement(); | |
| 431 | |
| 432 return waitable_event_.TimedWait(max_time); | |
| 433 } | |
| 434 | |
| 435 } // namespace | |
| 436 | |
| 382 void BrowserProcessImpl::EndSession() { | 437 void BrowserProcessImpl::EndSession() { |
| 383 // Mark all the profiles as clean. | 438 // Mark all the profiles as clean. |
| 384 ProfileManager* pm = profile_manager(); | 439 ProfileManager* pm = profile_manager(); |
| 385 std::vector<Profile*> profiles(pm->GetLoadedProfiles()); | 440 std::vector<Profile*> profiles(pm->GetLoadedProfiles()); |
| 386 for (size_t i = 0; i < profiles.size(); ++i) | 441 scoped_refptr<RundownTaskCounter> rundown_counter(new RundownTaskCounter()); |
| 387 profiles[i]->SetExitType(Profile::EXIT_SESSION_ENDED); | 442 for (size_t i = 0; i < profiles.size(); ++i) { |
| 443 Profile* profile = profiles[i]; | |
| 444 profile->SetExitType(Profile::EXIT_SESSION_ENDED); | |
| 445 | |
| 446 rundown_counter->Post(profile->GetIOTaskRunner()); | |
| 447 } | |
| 388 | 448 |
| 389 // Tell the metrics service it was cleanly shutdown. | 449 // Tell the metrics service it was cleanly shutdown. |
| 390 MetricsService* metrics = g_browser_process->metrics_service(); | 450 MetricsService* metrics = g_browser_process->metrics_service(); |
| 391 if (metrics && local_state()) { | 451 if (metrics && local_state()) { |
| 392 metrics->RecordStartOfSessionEnd(); | 452 metrics->RecordStartOfSessionEnd(); |
| 393 #if !defined(OS_CHROMEOS) | 453 #if !defined(OS_CHROMEOS) |
| 394 // MetricsService lazily writes to prefs, force it to write now. | 454 // MetricsService lazily writes to prefs, force it to write now. |
| 395 // On ChromeOS, chrome gets killed when hangs, so no need to | 455 // On ChromeOS, chrome gets killed when hangs, so no need to |
| 396 // commit metrics::prefs::kStabilitySessionEndCompleted change immediately. | 456 // commit metrics::prefs::kStabilitySessionEndCompleted change immediately. |
| 397 local_state()->CommitPendingWrite(); | 457 local_state()->CommitPendingWrite(); |
| 458 | |
| 459 rundown_counter->Post(local_state_task_runner_); | |
|
gab
2014/06/25 14:21:50
This only happens inside the "if (metrics && local
Sigurður Ásgeirsson
2014/06/25 15:05:02
Apparently things work differently for local state
| |
| 398 #endif | 460 #endif |
| 399 } | 461 } |
| 400 | 462 |
| 401 // http://crbug.com/125207 | 463 // http://crbug.com/125207 |
| 402 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 464 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 403 | 465 |
| 404 // We must write that the profile and metrics service shutdown cleanly, | 466 // We must write that the profile and metrics service shutdown cleanly, |
| 405 // otherwise on startup we'll think we crashed. So we block until done and | 467 // otherwise on startup we'll think we crashed. So we block until done and |
| 406 // then proceed with normal shutdown. | 468 // then proceed with normal shutdown. |
| 407 #if defined(USE_X11) || defined(OS_WIN) | 469 #if defined(USE_X11) || defined(OS_WIN) |
| 408 // Create a waitable event to block on file writing being complete. | 470 // Do a best-effort wait on the successful countdown of rundown tasks. Note |
| 471 // that if we don't complete "quickly enough", Windows will terminate our | |
|
gab
2014/06/25 14:21:50
Can you quantify "quickly enough" based on documen
Sigurður Ásgeirsson
2014/06/25 15:05:02
The timeout is documented something like 5 seconds
| |
| 472 // process. | |
| 409 // | 473 // |
| 410 // On Windows, we previously posted a message to FILE and then ran a nested | 474 // On Windows, we previously posted a message to FILE and then ran a nested |
| 411 // message loop, waiting for that message to be processed until quitting. | 475 // message loop, waiting for that message to be processed until quitting. |
| 412 // However, doing so means that other messages will also be processed. In | 476 // However, doing so means that other messages will also be processed. In |
| 413 // particular, if the GPU process host notices that the GPU has been killed | 477 // particular, if the GPU process host notices that the GPU has been killed |
| 414 // during shutdown, it races exiting the nested loop with the process host | 478 // during shutdown, it races exiting the nested loop with the process host |
| 415 // blocking the message loop attempting to re-establish a connection to the | 479 // blocking the message loop attempting to re-establish a connection to the |
| 416 // GPU process synchronously. Because the system may not be allowing | 480 // GPU process synchronously. Because the system may not be allowing |
| 417 // processes to launch, this can result in a hang. See | 481 // processes to launch, this can result in a hang. See |
| 418 // http://crbug.com/318527. | 482 // http://crbug.com/318527. |
| 419 scoped_ptr<base::WaitableEvent> done_writing( | 483 rundown_counter->TimedWait( |
| 420 new base::WaitableEvent(false, false)); | 484 base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds)); |
| 421 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
| 422 base::Bind(Signal, done_writing.get())); | |
| 423 // If all file writes haven't cleared in the timeout, leak the WaitableEvent | |
| 424 // so that there's no race to reference it in Signal(). | |
| 425 if (!done_writing->TimedWait( | |
| 426 base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds))) { | |
| 427 ignore_result(done_writing.release()); | |
| 428 } | |
| 429 #else | 485 #else |
| 430 NOTIMPLEMENTED(); | 486 NOTIMPLEMENTED(); |
| 431 #endif | 487 #endif |
| 432 } | 488 } |
| 433 | 489 |
| 434 MetricsServicesManager* BrowserProcessImpl::GetMetricsServicesManager() { | 490 MetricsServicesManager* BrowserProcessImpl::GetMetricsServicesManager() { |
| 435 DCHECK(CalledOnValidThread()); | 491 DCHECK(CalledOnValidThread()); |
| 436 if (!metrics_services_manager_) | 492 if (!metrics_services_manager_) |
| 437 metrics_services_manager_.reset(new MetricsServicesManager(local_state())); | 493 metrics_services_manager_.reset(new MetricsServicesManager(local_state())); |
| 438 return metrics_services_manager_.get(); | 494 return metrics_services_manager_.get(); |
| (...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1101 } | 1157 } |
| 1102 | 1158 |
| 1103 void BrowserProcessImpl::OnAutoupdateTimer() { | 1159 void BrowserProcessImpl::OnAutoupdateTimer() { |
| 1104 if (CanAutorestartForUpdate()) { | 1160 if (CanAutorestartForUpdate()) { |
| 1105 DLOG(WARNING) << "Detected update. Restarting browser."; | 1161 DLOG(WARNING) << "Detected update. Restarting browser."; |
| 1106 RestartBackgroundInstance(); | 1162 RestartBackgroundInstance(); |
| 1107 } | 1163 } |
| 1108 } | 1164 } |
| 1109 | 1165 |
| 1110 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) | 1166 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) |
| OLD | NEW |