1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef MEDIA_AUDIO_AUDIO_THREAD_HANG_MONITOR_H_ 6 #define MEDIA_AUDIO_AUDIO_THREAD_HANG_MONITOR_H_ 7 8 #include "media/audio/audio_manager.h" 9 10 #include <atomic> 11 #include <memory> 12 13 #include "base/callback_forward.h" 14 #include "base/gtest_prod_util.h" 15 #include "base/macros.h" 16 #include "base/memory/ref_counted.h" 17 #include "base/memory/scoped_refptr.h" 18 #include "base/optional.h" 19 #include "base/sequence_checker.h" 20 #include "base/sequenced_task_runner.h" 21 #include "base/time/time.h" 22 #include "base/timer/timer.h" 23 #include "media/base/media_export.h" 24 25 namespace base { 26 class TickClock; 27 class SingleThreadTaskRunner; 28 } // namespace base 29 30 namespace media { 31 32 // This class detects if the audio manager thread is hung. It logs a histogram, 33 // and can optionally (if |dump_on_hang| is set) upload a crash dump when a hang 34 // is detected. It runs on a task runner from the task scheduler. It works by 35 // posting a task to the audio thread every minute and checking that it was 36 // executed. If three consecutive such pings are missed, the thread is 37 // considered hung. 38 class MEDIA_EXPORT AudioThreadHangMonitor final { 39 public: 40 using Ptr = 41 std::unique_ptr<AudioThreadHangMonitor, base::OnTaskRunnerDeleter>; 42 43 // These values are histogrammed over time; do not change their ordinal 44 // values. 45 enum class ThreadStatus { 46 // kNone = 0, obsolete. 47 kStarted = 1, 48 kHung, 49 kRecovered, 50 kMaxValue = kRecovered 51 }; 52 53 enum class HangAction { 54 // Do nothing. (UMA logging is always done.) 55 kDoNothing, 56 // A crash dump will be collected the first time the thread is detected as 57 // hung (note that no actual crashing is involved). 58 kDump, 59 // Terminate the current process with exit code 0. 60 kTerminateCurrentProcess, 61 // Terminate the current process with exit code 1, which yields a crash 62 // dump. 63 kDumpAndTerminateCurrentProcess 64 }; 65 66 // |monitor_task_runner| may be set explicitly by tests only. Other callers 67 // should use the default. If |hang_deadline| is not provided, or if it's 68 // zero, a default value is used. 69 static Ptr Create( 70 HangAction hang_action, 71 base::Optional<base::TimeDelta> hang_deadline, 72 const base::TickClock* clock, 73 scoped_refptr<base::SingleThreadTaskRunner> audio_thread_task_runner, 74 scoped_refptr<base::SequencedTaskRunner> monitor_task_runner = nullptr); 75 76 ~AudioThreadHangMonitor(); 77 78 // Thread-safe. 79 bool IsAudioThreadHung() const; 80 81 private: 82 friend class AudioThreadHangMonitorTest; 83 84 class SharedAtomicFlag final 85 : public base::RefCountedThreadSafe<SharedAtomicFlag> { 86 public: 87 SharedAtomicFlag(); 88 89 std::atomic_bool flag_ = {false}; 90 91 private: 92 friend class base::RefCountedThreadSafe<SharedAtomicFlag>; 93 ~SharedAtomicFlag(); 94 }; 95 96 AudioThreadHangMonitor( 97 HangAction hang_action, 98 base::Optional<base::TimeDelta> hang_deadline, 99 const base::TickClock* clock, 100 scoped_refptr<base::SingleThreadTaskRunner> audio_thread_task_runner); 101 102 void StartTimer(); 103 104 bool NeverLoggedThreadHung() const; 105 bool NeverLoggedThreadRecoveredAfterHung() const; 106 107 // This function is run by the |timer_|. It checks if the audio thread has 108 // shown signs of life since the last time it was called (by checking the 109 // |alive_flag_|) and updates the value of |successful_pings_| and 110 // |failed_pings_| as appropriate. It also changes the thread status and logs 111 // its value to a histogram. 112 void CheckIfAudioThreadIsAlive(); 113 114 // LogHistogramThreadStatus logs |thread_status_| to a histogram. 115 void LogHistogramThreadStatus(); 116 117 // For tests. See below functions. 118 void SetHangActionCallbacksForTesting( 119 base::RepeatingClosure dump_callback, 120 base::RepeatingClosure terminate_process_callback); 121 122 // Thin wrapper functions that either executes the default or runs a callback 123 // set with SetHangActioncallbacksForTesting(), for testing purposes. 124 void DumpWithoutCrashing(); 125 void TerminateCurrentProcess(); 126 127 const base::TickClock* const clock_; 128 129 // This flag is set to false on the monitor sequence and then set to true on 130 // the audio thread to indicate that the audio thread is alive. 131 const scoped_refptr<SharedAtomicFlag> alive_flag_; 132 133 // |audio_task_runner_| is the task runner of the audio thread. 134 const scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_; 135 136 // Which action(s) to take when detected hung thread. 137 const HangAction hang_action_; 138 139 // At which interval to ping and see if the thread is running. 140 const base::TimeDelta ping_interval_; 141 142 // For testing. See DumpWithoutCrashing() and TerminateCurrentProcess(). 143 base::RepeatingClosure dump_callback_; 144 base::RepeatingClosure terminate_process_callback_; 145 146 std::atomic<ThreadStatus> audio_thread_status_ = {ThreadStatus::kStarted}; 147 148 // All fields below are accessed on |monitor_sequence|. 149 SEQUENCE_CHECKER(monitor_sequence_); 150 151 // Timer to check |alive_flag_| regularly. 152 base::RepeatingTimer timer_; 153 154 // This variable is used to check to detect suspend/resume cycles. 155 // If a long time has passed since the timer was last fired, it is likely due 156 // to the machine being suspended. In such a case, we want to avoid falsely 157 // detecting the audio thread as hung. 158 base::TimeTicks last_check_time_ = base::TimeTicks(); 159 160 // |recent_ping_state_| tracks the recent life signs from the audio thread. If 161 // the most recent ping was successful, the number indicates the number of 162 // successive successful pings. If the most recent ping was failed, the number 163 // is the negative of the number of successive failed pings. 164 int recent_ping_state_ = 0; 165 166 DISALLOW_COPY_AND_ASSIGN(AudioThreadHangMonitor); 167 }; 168 169 } // namespace media 170 171 #endif // MEDIA_AUDIO_AUDIO_THREAD_HANG_MONITOR_H_ 172