audio_thread_hang_monitor.h 5.9 KB

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