123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef MEDIA_AUDIO_AUDIO_THREAD_HANG_MONITOR_H_
- #define MEDIA_AUDIO_AUDIO_THREAD_HANG_MONITOR_H_
- #include "base/memory/raw_ptr.h"
- #include "media/audio/audio_manager.h"
- #include <atomic>
- #include <memory>
- #include "base/callback_forward.h"
- #include "base/gtest_prod_util.h"
- #include "base/memory/ref_counted.h"
- #include "base/memory/scoped_refptr.h"
- #include "base/sequence_checker.h"
- #include "base/task/sequenced_task_runner.h"
- #include "base/time/time.h"
- #include "base/timer/timer.h"
- #include "media/base/media_export.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace base {
- class TickClock;
- class SingleThreadTaskRunner;
- } // namespace base
- namespace media {
- // This class detects if the audio manager thread is hung. It logs a histogram,
- // and can optionally (if |dump_on_hang| is set) upload a crash dump when a hang
- // is detected. It runs on a task runner from the task scheduler. It works by
- // posting a task to the audio thread every minute and checking that it was
- // executed. If three consecutive such pings are missed, the thread is
- // considered hung.
- class MEDIA_EXPORT AudioThreadHangMonitor final {
- public:
- using Ptr =
- std::unique_ptr<AudioThreadHangMonitor, base::OnTaskRunnerDeleter>;
- // These values are histogrammed over time; do not change their ordinal
- // values.
- enum class ThreadStatus {
- // kNone = 0, obsolete.
- kStarted = 1,
- kHung,
- kRecovered,
- kMaxValue = kRecovered
- };
- enum class HangAction {
- // Do nothing. (UMA logging is always done.)
- kDoNothing,
- // A crash dump will be collected the first time the thread is detected as
- // hung (note that no actual crashing is involved).
- kDump,
- // Terminate the current process with exit code 0.
- kTerminateCurrentProcess,
- // Terminate the current process with exit code 1, which yields a crash
- // dump.
- kDumpAndTerminateCurrentProcess
- };
- // |monitor_task_runner| may be set explicitly by tests only. Other callers
- // should use the default. If |hang_deadline| is not provided, or if it's
- // zero, a default value is used.
- static Ptr Create(
- HangAction hang_action,
- absl::optional<base::TimeDelta> hang_deadline,
- const base::TickClock* clock,
- scoped_refptr<base::SingleThreadTaskRunner> audio_thread_task_runner,
- scoped_refptr<base::SequencedTaskRunner> monitor_task_runner = nullptr);
- AudioThreadHangMonitor(const AudioThreadHangMonitor&) = delete;
- AudioThreadHangMonitor& operator=(const AudioThreadHangMonitor&) = delete;
- ~AudioThreadHangMonitor();
- // Thread-safe.
- bool IsAudioThreadHung() const;
- private:
- friend class AudioThreadHangMonitorTest;
- class SharedAtomicFlag final
- : public base::RefCountedThreadSafe<SharedAtomicFlag> {
- public:
- SharedAtomicFlag();
- std::atomic_bool flag_ = {false};
- private:
- friend class base::RefCountedThreadSafe<SharedAtomicFlag>;
- ~SharedAtomicFlag();
- };
- AudioThreadHangMonitor(
- HangAction hang_action,
- absl::optional<base::TimeDelta> hang_deadline,
- const base::TickClock* clock,
- scoped_refptr<base::SingleThreadTaskRunner> audio_thread_task_runner);
- void StartTimer();
- bool NeverLoggedThreadHung() const;
- bool NeverLoggedThreadRecoveredAfterHung() const;
- // This function is run by the |timer_|. It checks if the audio thread has
- // shown signs of life since the last time it was called (by checking the
- // |alive_flag_|) and updates the value of |successful_pings_| and
- // |failed_pings_| as appropriate. It also changes the thread status and logs
- // its value to a histogram.
- void CheckIfAudioThreadIsAlive();
- // LogHistogramThreadStatus logs |thread_status_| to a histogram.
- void LogHistogramThreadStatus();
- // For tests. See below functions.
- void SetHangActionCallbacksForTesting(
- base::RepeatingClosure dump_callback,
- base::RepeatingClosure terminate_process_callback);
- // Thin wrapper functions that either executes the default or runs a callback
- // set with SetHangActioncallbacksForTesting(), for testing purposes.
- void DumpWithoutCrashing();
- void TerminateCurrentProcess();
- const raw_ptr<const base::TickClock> clock_;
- // This flag is set to false on the monitor sequence and then set to true on
- // the audio thread to indicate that the audio thread is alive.
- const scoped_refptr<SharedAtomicFlag> alive_flag_;
- // |audio_task_runner_| is the task runner of the audio thread.
- const scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_;
- // Which action(s) to take when detected hung thread.
- const HangAction hang_action_;
- // At which interval to ping and see if the thread is running.
- const base::TimeDelta ping_interval_;
- // For testing. See DumpWithoutCrashing() and TerminateCurrentProcess().
- base::RepeatingClosure dump_callback_;
- base::RepeatingClosure terminate_process_callback_;
- std::atomic<ThreadStatus> audio_thread_status_ = {ThreadStatus::kStarted};
- // All fields below are accessed on |monitor_sequence|.
- SEQUENCE_CHECKER(monitor_sequence_);
- // Timer to check |alive_flag_| regularly.
- base::RepeatingTimer timer_;
- // This variable is used to check to detect suspend/resume cycles.
- // If a long time has passed since the timer was last fired, it is likely due
- // to the machine being suspended. In such a case, we want to avoid falsely
- // detecting the audio thread as hung.
- base::TimeTicks last_check_time_ = base::TimeTicks();
- // |recent_ping_state_| tracks the recent life signs from the audio thread. If
- // the most recent ping was successful, the number indicates the number of
- // successive successful pings. If the most recent ping was failed, the number
- // is the negative of the number of successive failed pings.
- int recent_ping_state_ = 0;
- };
- } // namespace media
- #endif // MEDIA_AUDIO_AUDIO_THREAD_HANG_MONITOR_H_
|