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 |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 #if defined(OS_MACOSX) | 372 #if defined(OS_MACOSX) |
373 base::MessageLoop::current()->PostTask( | 373 base::MessageLoop::current()->PostTask( |
374 FROM_HERE, | 374 FROM_HERE, |
375 base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop)); | 375 base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop)); |
376 #endif | 376 #endif |
377 base::MessageLoop::current()->Quit(); | 377 base::MessageLoop::current()->Quit(); |
378 } | 378 } |
379 return module_ref_count_; | 379 return module_ref_count_; |
380 } | 380 } |
381 | 381 |
| 382 namespace { |
| 383 |
| 384 class RundownTaskCounter : |
| 385 public base::RefCountedThreadSafe<RundownTaskCounter> { |
| 386 public: |
| 387 // Creates a rundown task counter with |count|. |
| 388 explicit RundownTaskCounter(size_t count); |
| 389 |
| 390 |
| 391 // Decrements the counter and releases the wait on zero. |
| 392 static void Decrement(RundownTaskCounter* counter); |
| 393 |
| 394 // Waits until the count is zero or |max_time| has passed. |
| 395 bool TimedWait(const base::TimeDelta& max_time); |
| 396 |
| 397 private: |
| 398 friend class base::RefCountedThreadSafe<RundownTaskCounter>; |
| 399 ~RundownTaskCounter() {} |
| 400 |
| 401 base::AtomicRefCount count_; |
| 402 base::WaitableEvent waitable_event_; |
| 403 |
| 404 DISALLOW_COPY_AND_ASSIGN(RundownTaskCounter); |
| 405 }; |
| 406 |
| 407 RundownTaskCounter::RundownTaskCounter(size_t count) |
| 408 : count_(count), waitable_event_(true, false) { |
| 409 DCHECK_LT(1U, count); |
| 410 } |
| 411 |
| 412 void RundownTaskCounter::Decrement(RundownTaskCounter* counter) { |
| 413 DCHECK_NE(static_cast<RundownTaskCounter*>(NULL), counter); |
| 414 |
| 415 if (!base::AtomicRefCountDec(&counter->count_)) { |
| 416 counter->waitable_event_.Signal(); |
| 417 } |
| 418 } |
| 419 |
| 420 bool RundownTaskCounter::TimedWait(const base::TimeDelta& max_time) { |
| 421 return waitable_event_.TimedWait(max_time); |
| 422 } |
| 423 |
| 424 } // namespace |
| 425 |
382 void BrowserProcessImpl::EndSession() { | 426 void BrowserProcessImpl::EndSession() { |
383 // Mark all the profiles as clean. | 427 // Mark all the profiles as clean. |
384 ProfileManager* pm = profile_manager(); | 428 ProfileManager* pm = profile_manager(); |
385 std::vector<Profile*> profiles(pm->GetLoadedProfiles()); | 429 std::vector<Profile*> profiles(pm->GetLoadedProfiles()); |
386 for (size_t i = 0; i < profiles.size(); ++i) | 430 |
387 profiles[i]->SetExitType(Profile::EXIT_SESSION_ENDED); | 431 // We create the rundown task counter with a count for each profile, |
| 432 // plus one for local state. |
| 433 scoped_refptr<RundownTaskCounter> counter( |
| 434 new RundownTaskCounter(profiles.size() + 1)); |
| 435 |
| 436 for (size_t i = 0; i < profiles.size(); ++i) { |
| 437 Profile* profile = profiles[i]; |
| 438 profile->SetExitType(Profile::EXIT_SESSION_ENDED); |
| 439 |
| 440 scoped_refptr<base::SequencedTaskRunner> io_task_runner = |
| 441 profile->GetIOTaskRunner(); |
| 442 io_task_runner->PostTask(FROM_HERE, |
| 443 base::Bind(RundownTaskCounter::Decrement, |
| 444 counter.get())); |
| 445 } |
388 | 446 |
389 // Tell the metrics service it was cleanly shutdown. | 447 // Tell the metrics service it was cleanly shutdown. |
390 MetricsService* metrics = g_browser_process->metrics_service(); | 448 MetricsService* metrics = g_browser_process->metrics_service(); |
391 if (metrics && local_state()) { | 449 if (metrics && local_state()) { |
392 metrics->RecordStartOfSessionEnd(); | 450 metrics->RecordStartOfSessionEnd(); |
393 #if !defined(OS_CHROMEOS) | 451 #if !defined(OS_CHROMEOS) |
394 // MetricsService lazily writes to prefs, force it to write now. | 452 // MetricsService lazily writes to prefs, force it to write now. |
395 // On ChromeOS, chrome gets killed when hangs, so no need to | 453 // On ChromeOS, chrome gets killed when hangs, so no need to |
396 // commit metrics::prefs::kStabilitySessionEndCompleted change immediately. | 454 // commit metrics::prefs::kStabilitySessionEndCompleted change immediately. |
397 local_state()->CommitPendingWrite(); | 455 local_state()->CommitPendingWrite(); |
| 456 |
| 457 local_state_task_runner_->PostTask(FROM_HERE, |
| 458 base::Bind(RundownTaskCounter::Decrement, |
| 459 counter.get())); |
| 460 |
398 #endif | 461 #endif |
399 } | 462 } |
400 | 463 |
401 // http://crbug.com/125207 | 464 // http://crbug.com/125207 |
402 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 465 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
403 | 466 |
404 // We must write that the profile and metrics service shutdown cleanly, | 467 // 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 | 468 // otherwise on startup we'll think we crashed. So we block until done and |
406 // then proceed with normal shutdown. | 469 // then proceed with normal shutdown. |
407 #if defined(USE_X11) || defined(OS_WIN) | 470 #if defined(USE_X11) || defined(OS_WIN) |
408 // Create a waitable event to block on file writing being complete. | 471 // Do a best-effort wait on the successful countdown of rundown tasks. Note |
| 472 // that if we don't complete "quickly enough", Windows will terminate our |
| 473 // process. |
409 // | 474 // |
410 // On Windows, we previously posted a message to FILE and then ran a nested | 475 // 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. | 476 // message loop, waiting for that message to be processed until quitting. |
412 // However, doing so means that other messages will also be processed. In | 477 // 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 | 478 // 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 | 479 // 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 | 480 // blocking the message loop attempting to re-establish a connection to the |
416 // GPU process synchronously. Because the system may not be allowing | 481 // GPU process synchronously. Because the system may not be allowing |
417 // processes to launch, this can result in a hang. See | 482 // processes to launch, this can result in a hang. See |
418 // http://crbug.com/318527. | 483 // http://crbug.com/318527. |
419 scoped_ptr<base::WaitableEvent> done_writing( | 484 counter.get()->TimedWait( |
420 new base::WaitableEvent(false, false)); | 485 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 | 486 #else |
430 NOTIMPLEMENTED(); | 487 NOTIMPLEMENTED(); |
431 #endif | 488 #endif |
432 } | 489 } |
433 | 490 |
434 MetricsServicesManager* BrowserProcessImpl::GetMetricsServicesManager() { | 491 MetricsServicesManager* BrowserProcessImpl::GetMetricsServicesManager() { |
435 DCHECK(CalledOnValidThread()); | 492 DCHECK(CalledOnValidThread()); |
436 if (!metrics_services_manager_) | 493 if (!metrics_services_manager_) |
437 metrics_services_manager_.reset(new MetricsServicesManager(local_state())); | 494 metrics_services_manager_.reset(new MetricsServicesManager(local_state())); |
438 return metrics_services_manager_.get(); | 495 return metrics_services_manager_.get(); |
(...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1101 } | 1158 } |
1102 | 1159 |
1103 void BrowserProcessImpl::OnAutoupdateTimer() { | 1160 void BrowserProcessImpl::OnAutoupdateTimer() { |
1104 if (CanAutorestartForUpdate()) { | 1161 if (CanAutorestartForUpdate()) { |
1105 DLOG(WARNING) << "Detected update. Restarting browser."; | 1162 DLOG(WARNING) << "Detected update. Restarting browser."; |
1106 RestartBackgroundInstance(); | 1163 RestartBackgroundInstance(); |
1107 } | 1164 } |
1108 } | 1165 } |
1109 | 1166 |
1110 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) | 1167 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) |
OLD | NEW |