Chromium Code Reviews| Index: media/audio/audio_manager.cc |
| diff --git a/media/audio/audio_manager.cc b/media/audio/audio_manager.cc |
| index 6d5d70d087c204d29df1714536b18e032ccd2374..cad09a599cd76e0074bcbc529c1c99893dba252b 100644 |
| --- a/media/audio/audio_manager.cc |
| +++ b/media/audio/audio_manager.cc |
| @@ -14,7 +14,58 @@ |
| namespace media { |
| namespace { |
| AudioManager* g_last_created = NULL; |
| -static base::LazyInstance<FakeAudioLogFactory>::Leaky g_fake_log_factory = |
| + |
| +// Helper class for managing global AudioManager data and hang timers. If the |
| +// audio thread is unresponsive for more than a minute we want to crash the |
| +// process so we can catch offenders quickly in the field. |
| +class AudioManagerHelper { |
| + public: |
| + AudioManagerHelper() : max_hung_task_time_(base::TimeDelta::FromMinutes(1)) {} |
| + ~AudioManagerHelper() {} |
| + |
| + void StartHangTimer( |
| + const scoped_refptr<base::SingleThreadTaskRunner>& monitor_task_runner) { |
| + CHECK(!monitor_task_runner_); |
|
nasko
2015/03/25 17:28:00
nit: Can we also check that this is called on the
DaleCurtis
2015/03/25 20:28:56
Sent you a chat about this, because I'm not clear
nasko
2015/03/25 20:52:23
Clarified over chat. Since this method isn't expec
|
| + monitor_task_runner_ = monitor_task_runner; |
| + UpdateLastAudioThreadTimeTick(); |
| + CrashOnAudioThreadHang(); |
| + } |
| + |
| + void CrashOnAudioThreadHang() { |
| + base::AutoLock lock(hang_lock_); |
| + CHECK(base::TimeTicks::Now() - last_audio_thread_timer_tick_ <= |
| + max_hung_task_time_); |
| + monitor_task_runner_->PostDelayedTask( |
| + FROM_HERE, base::Bind(&AudioManagerHelper::CrashOnAudioThreadHang, |
| + base::Unretained(this)), |
|
nasko
2015/03/25 17:28:00
Are we guaranteed that this object will never be n
DaleCurtis
2015/03/25 20:28:56
Yes, it's a LazyInstance::Leaky, which means it'll
nasko
2015/03/25 20:52:23
Acknowledged.
|
| + max_hung_task_time_); |
| + } |
| + |
| + void UpdateLastAudioThreadTimeTick() { |
| + base::AutoLock lock(hang_lock_); |
| + last_audio_thread_timer_tick_ = base::TimeTicks::Now(); |
| + g_last_created->GetTaskRunner()->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&AudioManagerHelper::UpdateLastAudioThreadTimeTick, |
| + base::Unretained(this)), |
| + max_hung_task_time_ / 2); |
| + } |
| + |
| + AudioLogFactory* fake_log_factory() { return &fake_log_factory_; } |
| + |
| + private: |
| + FakeAudioLogFactory fake_log_factory_; |
| + |
| + const base::TimeDelta max_hung_task_time_; |
| + scoped_refptr<base::SingleThreadTaskRunner> monitor_task_runner_; |
| + |
| + base::Lock hang_lock_; |
| + base::TimeTicks last_audio_thread_timer_tick_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(AudioManagerHelper); |
| +}; |
| + |
| +static base::LazyInstance<AudioManagerHelper>::Leaky g_helper = |
| LAZY_INSTANCE_INITIALIZER; |
| } |
| @@ -36,8 +87,17 @@ AudioManager* AudioManager::Create(AudioLogFactory* audio_log_factory) { |
| } |
| // static |
| +AudioManager* AudioManager::CreateWithHangTimer( |
| + AudioLogFactory* audio_log_factory, |
| + const scoped_refptr<base::SingleThreadTaskRunner>& monitor_task_runner) { |
| + AudioManager* manager = Create(audio_log_factory); |
| + g_helper.Pointer()->StartHangTimer(monitor_task_runner); |
| + return manager; |
| +} |
| + |
| +// static |
| AudioManager* AudioManager::CreateForTesting() { |
| - return Create(g_fake_log_factory.Pointer()); |
| + return Create(g_helper.Pointer()->fake_log_factory()); |
| } |
| // static |