• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/threading/hang_watcher.h"
6 #include <atomic>
7 #include <memory>
8 
9 #include "base/barrier_closure.h"
10 #include "base/functional/bind.h"
11 #include "base/functional/callback.h"
12 #include "base/functional/callback_helpers.h"
13 #include "base/memory/raw_ptr.h"
14 #include "base/metrics/field_trial_params.h"
15 #include "base/run_loop.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/synchronization/lock.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "base/test/bind.h"
20 #include "base/test/metrics/histogram_tester.h"
21 #include "base/test/power_monitor_test.h"
22 #include "base/test/scoped_feature_list.h"
23 #include "base/test/simple_test_tick_clock.h"
24 #include "base/test/task_environment.h"
25 #include "base/test/test_timeouts.h"
26 #include "base/threading/platform_thread.h"
27 #include "base/threading/thread_checker.h"
28 #include "base/threading/threading_features.h"
29 #include "base/time/tick_clock.h"
30 #include "base/time/time.h"
31 #include "build/build_config.h"
32 #include "testing/gmock/include/gmock/gmock.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34 #include "third_party/abseil-cpp/absl/types/optional.h"
35 
36 using testing::ElementsAre;
37 using testing::IsEmpty;
38 
39 namespace base {
40 namespace {
41 
42 // Use with a FeatureList to activate crash dumping for threads marked as
43 // threadpool threads.
44 const std::vector<base::test::FeatureRefAndParams> kFeatureAndParams{
45     {base::kEnableHangWatcher, {{"ui_thread_log_level", "2"}}}};
46 
47 // Use this value to mark things very far off in the future. Adding this
48 // to TimeTicks::Now() gives a point that will never be reached during the
49 // normal execution of a test.
50 constexpr TimeDelta kVeryLongDelta{base::Days(365)};
51 
52 // A relatively small time delta to ensure ordering of hung threads list.
53 constexpr TimeDelta kSmallCPUQuantum{base::Milliseconds(1)};
54 
55 constexpr uint64_t kArbitraryDeadline = 0x0000C0FFEEC0FFEEu;
56 constexpr uint64_t kAllOnes = 0xFFFFFFFFFFFFFFFFu;
57 constexpr uint64_t kAllZeros = 0x0000000000000000u;
58 constexpr uint64_t kOnesThenZeroes = 0xAAAAAAAAAAAAAAAAu;
59 constexpr uint64_t kZeroesThenOnes = 0x5555555555555555u;
60 
61 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
62 class HangWatcherEnabledInZygoteChildTest
63     : public testing::TestWithParam<std::tuple<bool, bool>> {
64  public:
HangWatcherEnabledInZygoteChildTest()65   HangWatcherEnabledInZygoteChildTest() {
66     std::vector<base::test::FeatureRefAndParams> enabled_features =
67         kFeatureAndParams;
68     std::vector<test::FeatureRef> disabled_features;
69     if (std::get<0>(GetParam())) {
70       enabled_features.push_back(test::FeatureRefAndParams(
71           base::kEnableHangWatcherInZygoteChildren, {}));
72     } else {
73       disabled_features.push_back(base::kEnableHangWatcherInZygoteChildren);
74     }
75     feature_list_.InitWithFeaturesAndParameters(enabled_features,
76                                                 disabled_features);
77     HangWatcher::InitializeOnMainThread(
78         HangWatcher::ProcessType::kUtilityProcess,
79         /*is_zygote_child=*/std::get<1>(GetParam()));
80   }
81 
TearDown()82   void TearDown() override { HangWatcher::UnitializeOnMainThreadForTesting(); }
83 
84   HangWatcherEnabledInZygoteChildTest(
85       const HangWatcherEnabledInZygoteChildTest& other) = delete;
86   HangWatcherEnabledInZygoteChildTest& operator=(
87       const HangWatcherEnabledInZygoteChildTest& other) = delete;
88 
89  protected:
90   base::test::ScopedFeatureList feature_list_;
91 };
92 
TEST_P(HangWatcherEnabledInZygoteChildTest,IsEnabled)93 TEST_P(HangWatcherEnabledInZygoteChildTest, IsEnabled) {
94   // If the kEnableHangWatcherInZygoteChildren feature is disabled and
95   // InitializeOnMainThread is called with is_zygote_child==true, IsEnabled()
96   // should return false. It should return true in all other situations.
97   ASSERT_EQ(std::get<0>(GetParam()) || !std::get<1>(GetParam()),
98             HangWatcher::IsEnabled());
99 }
100 
101 INSTANTIATE_TEST_SUITE_P(HangWatcherZygoteTest,
102                          HangWatcherEnabledInZygoteChildTest,
103                          testing::Combine(testing::Bool(), testing::Bool()));
104 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
105 
106 // Waits on provided WaitableEvent before executing and signals when done.
107 class BlockingThread : public DelegateSimpleThread::Delegate {
108  public:
BlockingThread(base::WaitableEvent * unblock_thread,base::TimeDelta timeout)109   explicit BlockingThread(base::WaitableEvent* unblock_thread,
110                           base::TimeDelta timeout)
111       : thread_(this, "BlockingThread"),
112         unblock_thread_(unblock_thread),
113         timeout_(timeout) {}
114 
115   ~BlockingThread() override = default;
116 
Run()117   void Run() override {
118     // (Un)Register the thread here instead of in ctor/dtor so that the action
119     // happens on the right thread.
120     base::ScopedClosureRunner unregister_closure =
121         base::HangWatcher::RegisterThread(
122             base::HangWatcher::ThreadType::kMainThread);
123 
124     WatchHangsInScope scope(timeout_);
125     wait_until_entered_scope_.Signal();
126 
127     unblock_thread_->Wait();
128     run_event_.Signal();
129   }
130 
IsDone()131   bool IsDone() { return run_event_.IsSignaled(); }
132 
StartAndWaitForScopeEntered()133   void StartAndWaitForScopeEntered() {
134     thread_.Start();
135     // Block until this thread registered itself for hang watching and has
136     // entered a WatchHangsInScope.
137     wait_until_entered_scope_.Wait();
138   }
139 
Join()140   void Join() { thread_.Join(); }
141 
GetId()142   PlatformThreadId GetId() { return thread_.tid(); }
143 
144  private:
145   base::DelegateSimpleThread thread_;
146 
147   // Will be signaled once the thread is properly registered for watching and
148   // the WatchHangsInScope has been entered.
149   WaitableEvent wait_until_entered_scope_;
150 
151   // Will be signaled once ThreadMain has run.
152   WaitableEvent run_event_;
153 
154   const raw_ptr<base::WaitableEvent> unblock_thread_;
155 
156   base::TimeDelta timeout_;
157 };
158 
159 class HangWatcherTest : public testing::Test {
160  public:
161   const base::TimeDelta kTimeout = base::Seconds(10);
162   const base::TimeDelta kHangTime = kTimeout + base::Seconds(1);
163 
HangWatcherTest()164   HangWatcherTest() {
165     feature_list_.InitWithFeaturesAndParameters(kFeatureAndParams, {});
166     HangWatcher::InitializeOnMainThread(
167         HangWatcher::ProcessType::kBrowserProcess, false);
168 
169     hang_watcher_.SetAfterMonitorClosureForTesting(base::BindRepeating(
170         &WaitableEvent::Signal, base::Unretained(&monitor_event_)));
171 
172     hang_watcher_.SetOnHangClosureForTesting(base::BindRepeating(
173         &WaitableEvent::Signal, base::Unretained(&hang_event_)));
174 
175     // We're not testing the monitoring loop behavior in this test so we want to
176     // trigger monitoring manually.
177     hang_watcher_.SetMonitoringPeriodForTesting(kVeryLongDelta);
178 
179     // Start the monitoring loop.
180     hang_watcher_.Start();
181   }
182 
TearDown()183   void TearDown() override { HangWatcher::UnitializeOnMainThreadForTesting(); }
184 
185   HangWatcherTest(const HangWatcherTest& other) = delete;
186   HangWatcherTest& operator=(const HangWatcherTest& other) = delete;
187 
188  protected:
189   // Used to wait for monitoring. Will be signaled by the HangWatcher thread and
190   // so needs to outlive it.
191   WaitableEvent monitor_event_;
192 
193   // Signaled from the HangWatcher thread when a hang is detected. Needs to
194   // outlive the HangWatcher thread.
195   WaitableEvent hang_event_;
196 
197   base::test::ScopedFeatureList feature_list_;
198 
199   // Used exclusively for MOCK_TIME. No tasks will be run on the environment.
200   // Single threaded to avoid ThreadPool WorkerThreads registering.
201   test::SingleThreadTaskEnvironment task_environment_{
202       test::TaskEnvironment::TimeSource::MOCK_TIME};
203 
204   // This must be declared last (after task_environment_, for example) so that
205   // the watcher thread is joined before objects like the mock timer are
206   // destroyed, causing racy crashes.
207   HangWatcher hang_watcher_;
208 };
209 
210 class HangWatcherBlockingThreadTest : public HangWatcherTest {
211  public:
HangWatcherBlockingThreadTest()212   HangWatcherBlockingThreadTest() : thread_(&unblock_thread_, kTimeout) {}
213 
214   HangWatcherBlockingThreadTest(const HangWatcherBlockingThreadTest& other) =
215       delete;
216   HangWatcherBlockingThreadTest& operator=(
217       const HangWatcherBlockingThreadTest& other) = delete;
218 
219  protected:
JoinThread()220   void JoinThread() {
221     unblock_thread_.Signal();
222 
223     // Thread is joinable since we signaled |unblock_thread_|.
224     thread_.Join();
225 
226     // If thread is done then it signaled.
227     ASSERT_TRUE(thread_.IsDone());
228   }
229 
StartBlockedThread()230   void StartBlockedThread() {
231     // Thread has not run yet.
232     ASSERT_FALSE(thread_.IsDone());
233 
234     // Start the thread. It will block since |unblock_thread_| was not
235     // signaled yet.
236     thread_.StartAndWaitForScopeEntered();
237 
238     // Thread registration triggered a call to HangWatcher::Monitor() which
239     // signaled |monitor_event_|. Reset it so it's ready for waiting later on.
240     monitor_event_.Reset();
241   }
242 
MonitorHangs()243   void MonitorHangs() {
244     // HangWatcher::Monitor() should not be set which would mean a call to
245     // HangWatcher::Monitor() happened and was unacounted for.
246     // ASSERT_FALSE(monitor_event_.IsSignaled());
247 
248     // Trigger a monitoring on HangWatcher thread and verify results.
249     hang_watcher_.SignalMonitorEventForTesting();
250     monitor_event_.Wait();
251   }
252 
253   // Used to unblock the monitored thread. Signaled from the test main thread.
254   WaitableEvent unblock_thread_;
255 
256   BlockingThread thread_;
257 };
258 }  // namespace
259 
TEST_F(HangWatcherTest,InvalidatingExpectationsPreventsCapture)260 TEST_F(HangWatcherTest, InvalidatingExpectationsPreventsCapture) {
261   // Register the main test thread for hang watching.
262   auto unregister_thread_closure =
263       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
264 
265   // Create a hang.
266   WatchHangsInScope expires_instantly(base::TimeDelta{});
267   task_environment_.FastForwardBy(kHangTime);
268 
269   // de-activate hang watching,
270   base::HangWatcher::InvalidateActiveExpectations();
271 
272   // Trigger a monitoring on HangWatcher thread and verify results.
273   // Hang is not detected.
274   hang_watcher_.SignalMonitorEventForTesting();
275   monitor_event_.Wait();
276   ASSERT_FALSE(hang_event_.IsSignaled());
277 }
278 
TEST_F(HangWatcherTest,MultipleInvalidateExpectationsDoNotCancelOut)279 TEST_F(HangWatcherTest, MultipleInvalidateExpectationsDoNotCancelOut) {
280   // Register the main test thread for hang watching.
281   auto unregister_thread_closure =
282       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
283 
284   // Create a hang.
285   WatchHangsInScope expires_instantly(base::TimeDelta{});
286   task_environment_.FastForwardBy(kHangTime);
287 
288   // de-activate hang watching,
289   base::HangWatcher::InvalidateActiveExpectations();
290 
291   // Redundently de-activate hang watching.
292   base::HangWatcher::InvalidateActiveExpectations();
293 
294   // Trigger a monitoring on HangWatcher thread and verify results.
295   // Hang is not detected.
296   hang_watcher_.SignalMonitorEventForTesting();
297   monitor_event_.Wait();
298   ASSERT_FALSE(hang_event_.IsSignaled());
299 }
300 
TEST_F(HangWatcherTest,NewInnerWatchHangsInScopeAfterInvalidationDetectsHang)301 TEST_F(HangWatcherTest, NewInnerWatchHangsInScopeAfterInvalidationDetectsHang) {
302   // Register the main test thread for hang watching.
303   auto unregister_thread_closure =
304       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
305 
306   WatchHangsInScope expires_instantly(base::TimeDelta{});
307   task_environment_.FastForwardBy(kHangTime);
308 
309   // De-activate hang watching.
310   base::HangWatcher::InvalidateActiveExpectations();
311 
312   {
313     WatchHangsInScope also_expires_instantly(base::TimeDelta{});
314     task_environment_.FastForwardBy(kHangTime);
315 
316     // Trigger a monitoring on HangWatcher thread and verify results.
317     hang_watcher_.SignalMonitorEventForTesting();
318     monitor_event_.Wait();
319 
320     // Hang is detected since the new WatchHangsInScope temporarily
321     // re-activated hang_watching.
322     monitor_event_.Wait();
323     ASSERT_TRUE(hang_event_.IsSignaled());
324   }
325 
326   // Reset to attempt capture again.
327   monitor_event_.Reset();
328   hang_event_.Reset();
329 
330   // Trigger a monitoring on HangWatcher thread and verify results.
331   hang_watcher_.SignalMonitorEventForTesting();
332   monitor_event_.Wait();
333 
334   // Hang is not detected since execution is back to being covered by
335   // |expires_instantly| for which expectations were invalidated.
336   monitor_event_.Wait();
337   ASSERT_FALSE(hang_event_.IsSignaled());
338 }
339 
TEST_F(HangWatcherTest,NewSeparateWatchHangsInScopeAfterInvalidationDetectsHang)340 TEST_F(HangWatcherTest,
341        NewSeparateWatchHangsInScopeAfterInvalidationDetectsHang) {
342   // Register the main test thread for hang watching.
343   auto unregister_thread_closure =
344       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
345 
346   {
347     WatchHangsInScope expires_instantly(base::TimeDelta{});
348     task_environment_.FastForwardBy(kHangTime);
349 
350     // De-activate hang watching.
351     base::HangWatcher::InvalidateActiveExpectations();
352   }
353 
354   WatchHangsInScope also_expires_instantly(base::TimeDelta{});
355   task_environment_.FastForwardBy(kHangTime);
356 
357   // Trigger a monitoring on HangWatcher thread and verify results.
358   hang_watcher_.SignalMonitorEventForTesting();
359   monitor_event_.Wait();
360 
361   // Hang is detected since the new WatchHangsInScope did not have its
362   // expectations invalidated.
363   monitor_event_.Wait();
364   ASSERT_TRUE(hang_event_.IsSignaled());
365 }
366 
367 // Test that invalidating expectations from inner WatchHangsInScope will also
368 // prevent hang detection in outer scopes.
TEST_F(HangWatcherTest,ScopeDisabledObjectInnerScope)369 TEST_F(HangWatcherTest, ScopeDisabledObjectInnerScope) {
370   // Register the main test thread for hang watching.
371   auto unregister_thread_closure =
372       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
373 
374   // Start a WatchHangsInScope that expires right away. Then advance
375   // time to make sure no hang is detected.
376   WatchHangsInScope expires_instantly(base::TimeDelta{});
377   task_environment_.FastForwardBy(kHangTime);
378   {
379     WatchHangsInScope also_expires_instantly(base::TimeDelta{});
380 
381     // De-activate hang watching.
382     base::HangWatcher::InvalidateActiveExpectations();
383     task_environment_.FastForwardBy(kHangTime);
384   }
385 
386   // Trigger a monitoring on HangWatcher thread and verify results.
387   hang_watcher_.SignalMonitorEventForTesting();
388   monitor_event_.Wait();
389 
390   // Hang is ignored since it concerns a scope for which one of the inner scope
391   // was ignored.
392   ASSERT_FALSE(hang_event_.IsSignaled());
393 }
394 
TEST_F(HangWatcherTest,NewScopeAfterDisabling)395 TEST_F(HangWatcherTest, NewScopeAfterDisabling) {
396   // Register the main test thread for hang watching.
397   auto unregister_thread_closure =
398       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
399 
400   // Start a WatchHangsInScope that expires right away. Then advance
401   // time to make sure no hang is detected.
402   WatchHangsInScope expires_instantly(base::TimeDelta{});
403   task_environment_.FastForwardBy(kHangTime);
404   {
405     WatchHangsInScope also_expires_instantly(base::TimeDelta{});
406 
407     // De-activate hang watching.
408     base::HangWatcher::InvalidateActiveExpectations();
409     task_environment_.FastForwardBy(kHangTime);
410   }
411 
412   // New scope for which expecations are never invalidated.
413   WatchHangsInScope also_expires_instantly(base::TimeDelta{});
414   task_environment_.FastForwardBy(kHangTime);
415 
416   // Trigger a monitoring on HangWatcher thread and verify results.
417   hang_watcher_.SignalMonitorEventForTesting();
418   monitor_event_.Wait();
419 
420   // Hang is detected because it's unrelated to the hangs that were disabled.
421   ASSERT_TRUE(hang_event_.IsSignaled());
422 }
423 
TEST_F(HangWatcherTest,NestedScopes)424 TEST_F(HangWatcherTest, NestedScopes) {
425   // Create a state object for the test thread since this test is single
426   // threaded.
427   auto current_hang_watch_state =
428       base::internal::HangWatchState::CreateHangWatchStateForCurrentThread(
429           HangWatcher::ThreadType::kMainThread);
430 
431   ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
432   base::TimeTicks original_deadline = current_hang_watch_state->GetDeadline();
433 
434   constexpr base::TimeDelta kFirstTimeout(base::Milliseconds(500));
435   base::TimeTicks first_deadline = base::TimeTicks::Now() + kFirstTimeout;
436 
437   constexpr base::TimeDelta kSecondTimeout(base::Milliseconds(250));
438   base::TimeTicks second_deadline = base::TimeTicks::Now() + kSecondTimeout;
439 
440   // At this point we have not set any timeouts.
441   {
442     // Create a first timeout which is more restrictive than the default.
443     WatchHangsInScope first_scope(kFirstTimeout);
444 
445     // We are on mock time. There is no time advancement and as such no hangs.
446     ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
447     ASSERT_EQ(current_hang_watch_state->GetDeadline(), first_deadline);
448     {
449       // Set a yet more restrictive deadline. Still no hang.
450       WatchHangsInScope second_scope(kSecondTimeout);
451       ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
452       ASSERT_EQ(current_hang_watch_state->GetDeadline(), second_deadline);
453     }
454     // First deadline we set should be restored.
455     ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
456     ASSERT_EQ(current_hang_watch_state->GetDeadline(), first_deadline);
457   }
458 
459   // Original deadline should now be restored.
460   ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
461   ASSERT_EQ(current_hang_watch_state->GetDeadline(), original_deadline);
462 }
463 
TEST_F(HangWatcherBlockingThreadTest,HistogramsLoggedOnHang)464 TEST_F(HangWatcherBlockingThreadTest, HistogramsLoggedOnHang) {
465   base::HistogramTester histogram_tester;
466   StartBlockedThread();
467 
468   // Simulate hang.
469   task_environment_.FastForwardBy(kHangTime);
470 
471   // First monitoring catches the hang and emits the histogram.
472   MonitorHangs();
473   EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
474                                              "BrowserProcess.UIThread"),
475               ElementsAre(base::Bucket(true, /*count=*/1)));
476 
477   // Reset to attempt capture again.
478   hang_event_.Reset();
479   monitor_event_.Reset();
480 
481   // Hang is logged again even if it would not trigger a crash dump.
482   MonitorHangs();
483   EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
484                                              "BrowserProcess.UIThread"),
485               ElementsAre(base::Bucket(true, /*count=*/2)));
486 
487   // Thread types that are not monitored should not get any samples.
488   EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
489                                              "BrowserProcess.IOThread"),
490               IsEmpty());
491   JoinThread();
492 }
493 
TEST_F(HangWatcherBlockingThreadTest,HistogramsLoggedWithoutHangs)494 TEST_F(HangWatcherBlockingThreadTest, HistogramsLoggedWithoutHangs) {
495   base::HistogramTester histogram_tester;
496   StartBlockedThread();
497 
498   // No hang to catch so nothing is recorded.
499   MonitorHangs();
500   ASSERT_FALSE(hang_event_.IsSignaled());
501 
502   // A thread of type ThreadForTesting was monitored but didn't hang. This is
503   // logged.
504   EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
505                                              "BrowserProcess.UIThread"),
506               ElementsAre(base::Bucket(false, /*count=*/1)));
507 
508   // Thread types that are not monitored should not get any samples.
509   EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
510                                              "BrowserProcess.IOThread"),
511               IsEmpty());
512   JoinThread();
513 }
514 
TEST_F(HangWatcherBlockingThreadTest,Hang)515 TEST_F(HangWatcherBlockingThreadTest, Hang) {
516   StartBlockedThread();
517 
518   // Simulate hang.
519   task_environment_.FastForwardBy(kHangTime);
520 
521   // First monitoring catches and records the hang.
522   MonitorHangs();
523   ASSERT_TRUE(hang_event_.IsSignaled());
524 
525   JoinThread();
526 }
527 
TEST_F(HangWatcherBlockingThreadTest,HangAlreadyRecorded)528 TEST_F(HangWatcherBlockingThreadTest, HangAlreadyRecorded) {
529   StartBlockedThread();
530 
531   // Simulate hang.
532   task_environment_.FastForwardBy(kHangTime);
533 
534   // First monitoring catches and records the hang.
535   MonitorHangs();
536   ASSERT_TRUE(hang_event_.IsSignaled());
537 
538   // Reset to attempt capture again.
539   hang_event_.Reset();
540   monitor_event_.Reset();
541 
542   // Second monitoring does not record because a hang that was already recorded
543   // is still live.
544   MonitorHangs();
545   ASSERT_FALSE(hang_event_.IsSignaled());
546 
547   JoinThread();
548 }
549 
TEST_F(HangWatcherBlockingThreadTest,NoHang)550 TEST_F(HangWatcherBlockingThreadTest, NoHang) {
551   StartBlockedThread();
552 
553   // No hang to catch so nothing is recorded.
554   MonitorHangs();
555   ASSERT_FALSE(hang_event_.IsSignaled());
556 
557   JoinThread();
558 }
559 
560 namespace {
561 class HangWatcherSnapshotTest : public testing::Test {
562  public:
SetUp()563   void SetUp() override {
564     feature_list_.InitWithFeaturesAndParameters(kFeatureAndParams, {});
565     HangWatcher::InitializeOnMainThread(
566         HangWatcher::ProcessType::kBrowserProcess, false);
567 
568     // The monitoring loop behavior is not verified in this test so we want to
569     // trigger monitoring manually.
570     hang_watcher_.SetMonitoringPeriodForTesting(kVeryLongDelta);
571   }
572 
TearDown()573   void TearDown() override { HangWatcher::UnitializeOnMainThreadForTesting(); }
574 
575   HangWatcherSnapshotTest() = default;
576   HangWatcherSnapshotTest(const HangWatcherSnapshotTest& other) = delete;
577   HangWatcherSnapshotTest& operator=(const HangWatcherSnapshotTest& other) =
578       delete;
579 
580  protected:
TriggerMonitorAndWaitForCompletion()581   void TriggerMonitorAndWaitForCompletion() {
582     monitor_event_.Reset();
583     hang_watcher_.SignalMonitorEventForTesting();
584     monitor_event_.Wait();
585   }
586 
587   // Verify that a capture takes place and that at the time of the capture the
588   // list of hung thread ids is correct.
TestIDList(const std::string & id_list)589   void TestIDList(const std::string& id_list) {
590     list_of_hung_thread_ids_during_capture_ = id_list;
591     task_environment_.AdvanceClock(kSmallCPUQuantum);
592     TriggerMonitorAndWaitForCompletion();
593     ASSERT_EQ(++reference_capture_count_, hang_capture_count_);
594   }
595 
596   // Verify that even if hang monitoring takes place no hangs are detected.
ExpectNoCapture()597   void ExpectNoCapture() {
598     int old_capture_count = hang_capture_count_;
599     task_environment_.AdvanceClock(kSmallCPUQuantum);
600     TriggerMonitorAndWaitForCompletion();
601     ASSERT_EQ(old_capture_count, hang_capture_count_);
602   }
603 
ConcatenateThreadIds(const std::vector<base::PlatformThreadId> & ids) const604   std::string ConcatenateThreadIds(
605       const std::vector<base::PlatformThreadId>& ids) const {
606     std::string result;
607     constexpr char kSeparator{'|'};
608 
609     for (PlatformThreadId id : ids) {
610       result += base::NumberToString(id) + kSeparator;
611     }
612 
613     return result;
614   }
615 
616   // Will be signaled once monitoring took place. Marks the end of the test.
617   WaitableEvent monitor_event_;
618 
619   const PlatformThreadId test_thread_id_ = PlatformThread::CurrentId();
620 
621   // This is written to by the test main thread and read from the hang watching
622   // thread. It does not need to be protected because access to it is
623   // synchronized by always setting before triggering the execution of the
624   // reading code through HangWatcher::SignalMonitorEventForTesting().
625   std::string list_of_hung_thread_ids_during_capture_;
626 
627   // This is written to by from the hang watching thread and read the test main
628   // thread. It does not need to be protected because access to it is
629   // synchronized by always reading  after monitor_event_ has been signaled.
630   int hang_capture_count_ = 0;
631 
632   // Increases at the same time as |hang_capture_count_| to test that capture
633   // actually took place.
634   int reference_capture_count_ = 0;
635 
636   std::string seconds_since_last_power_resume_crash_key_;
637 
638   base::test::ScopedFeatureList feature_list_;
639 
640   // Used exclusively for MOCK_TIME.
641   test::SingleThreadTaskEnvironment task_environment_{
642       test::TaskEnvironment::TimeSource::MOCK_TIME};
643 
644   HangWatcher hang_watcher_;
645 };
646 }  // namespace
647 
648 // Verify that the hang capture fails when marking a thread for blocking fails.
649 // This simulates a WatchHangsInScope completing between the time the hang
650 // was dected and the time it is recorded which would create a non-actionable
651 // report.
TEST_F(HangWatcherSnapshotTest,NonActionableReport)652 TEST_F(HangWatcherSnapshotTest, NonActionableReport) {
653   hang_watcher_.SetOnHangClosureForTesting(
654       base::BindLambdaForTesting([this]() { ++hang_capture_count_; }));
655   hang_watcher_.SetAfterMonitorClosureForTesting(
656       base::BindLambdaForTesting([this]() { monitor_event_.Signal(); }));
657 
658   hang_watcher_.Start();
659 
660   // Register the main test thread for hang watching.
661   auto unregister_thread_closure =
662       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
663   {
664     // Start a WatchHangsInScope that expires right away. Ensures that
665     // the first monitor will detect a hang.
666     WatchHangsInScope expires_instantly(base::TimeDelta{});
667 
668     internal::HangWatchState* current_hang_watch_state =
669         internal::HangWatchState::GetHangWatchStateForCurrentThread();
670 
671     // Simulate the deadline changing concurrently during the capture. This
672     // makes the capture fail since marking of the deadline fails.
673     ASSERT_NE(current_hang_watch_state->GetDeadline(),
674               base::TimeTicks::FromInternalValue(kArbitraryDeadline));
675     current_hang_watch_state->GetHangWatchDeadlineForTesting()
676         ->SetSwitchBitsClosureForTesting(
677             base::BindLambdaForTesting([]() { return kArbitraryDeadline; }));
678 
679     ExpectNoCapture();
680 
681     // Marking failed.
682     ASSERT_FALSE(current_hang_watch_state->IsFlagSet(
683         internal::HangWatchDeadline::Flag::kShouldBlockOnHang));
684 
685     current_hang_watch_state->GetHangWatchDeadlineForTesting()
686         ->ResetSwitchBitsClosureForTesting();
687   }
688 }
689 
690 // TODO(crbug.com/1223033): On MAC, the base::PlatformThread::CurrentId(...)
691 // should return the system wide IDs. The HungThreadIDs test fails because the
692 // reported process ids do not match.
693 #if BUILDFLAG(IS_MAC)
694 #define MAYBE_HungThreadIDs DISABLED_HungThreadIDs
695 #else
696 #define MAYBE_HungThreadIDs HungThreadIDs
697 #endif
698 
TEST_F(HangWatcherSnapshotTest,MAYBE_HungThreadIDs)699 TEST_F(HangWatcherSnapshotTest, MAYBE_HungThreadIDs) {
700   // During hang capture the list of hung threads should be populated.
701   hang_watcher_.SetOnHangClosureForTesting(base::BindLambdaForTesting([this]() {
702     EXPECT_EQ(hang_watcher_.GrabWatchStateSnapshotForTesting()
703                   .PrepareHungThreadListCrashKey(),
704               list_of_hung_thread_ids_during_capture_);
705     ++hang_capture_count_;
706   }));
707 
708   // When hang capture is over the list should be empty.
709   hang_watcher_.SetAfterMonitorClosureForTesting(
710       base::BindLambdaForTesting([this]() {
711         monitor_event_.Signal();
712       }));
713 
714   hang_watcher_.Start();
715 
716   // Register the main test thread for hang watching.
717   auto unregister_thread_closure =
718       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
719 
720   BlockingThread blocking_thread(&monitor_event_, base::TimeDelta{});
721   blocking_thread.StartAndWaitForScopeEntered();
722   {
723     // Ensure the blocking thread entered the scope before the main thread. This
724     // will guarantee an ordering while reporting the list of hung threads.
725     task_environment_.AdvanceClock(kSmallCPUQuantum);
726 
727     // Start a WatchHangsInScope that expires right away. Ensures that
728     // the first monitor will detect a hang. This scope will naturally have a
729     // later deadline than the one in |blocking_thread_| since it was created
730     // after.
731     WatchHangsInScope expires_instantly(base::TimeDelta{});
732 
733     // Hung thread list should contain the id the blocking thread and then the
734     // id of the test main thread since that is the order of increasing
735     // deadline.
736     TestIDList(
737         ConcatenateThreadIds({blocking_thread.GetId(), test_thread_id_}));
738 
739     // |expires_instantly| and the scope from |blocking_thread| are still live
740     // but already recorded so should be ignored.
741     ExpectNoCapture();
742 
743     // Thread is joinable since we signaled |monitor_event_|. This closes the
744     // scope in |blocking_thread|.
745     blocking_thread.Join();
746 
747     // |expires_instantly| is still live but already recorded so should be
748     // ignored.
749     ExpectNoCapture();
750   }
751 
752   // All HangWatchScopeEnables are over. There should be no capture.
753   ExpectNoCapture();
754 
755   // Once all recorded scopes are over creating a new one and monitoring will
756   // trigger a hang detection.
757   WatchHangsInScope expires_instantly(base::TimeDelta{});
758   TestIDList(ConcatenateThreadIds({test_thread_id_}));
759 }
760 
TEST_F(HangWatcherSnapshotTest,TimeSinceLastSystemPowerResumeCrashKey)761 TEST_F(HangWatcherSnapshotTest, TimeSinceLastSystemPowerResumeCrashKey) {
762   // Override the capture of hangs. Simulate a crash key capture.
763   hang_watcher_.SetOnHangClosureForTesting(base::BindLambdaForTesting([this]() {
764     ++hang_capture_count_;
765     seconds_since_last_power_resume_crash_key_ =
766         hang_watcher_.GetTimeSinceLastSystemPowerResumeCrashKeyValue();
767   }));
768 
769   // When hang capture is over, unblock the main thread.
770   hang_watcher_.SetAfterMonitorClosureForTesting(
771       base::BindLambdaForTesting([this]() { monitor_event_.Signal(); }));
772 
773   hang_watcher_.Start();
774 
775   // Register the main test thread for hang watching.
776   auto unregister_thread_closure =
777       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
778 
779   {
780     WatchHangsInScope expires_instantly(base::TimeDelta{});
781     task_environment_.AdvanceClock(kSmallCPUQuantum);
782 
783     TriggerMonitorAndWaitForCompletion();
784     EXPECT_EQ(1, hang_capture_count_);
785     EXPECT_EQ("Never suspended", seconds_since_last_power_resume_crash_key_);
786   }
787 
788   {
789     test::ScopedPowerMonitorTestSource power_monitor_source;
790     power_monitor_source.Suspend();
791     task_environment_.AdvanceClock(kSmallCPUQuantum);
792 
793     {
794       WatchHangsInScope expires_instantly(base::TimeDelta{});
795       task_environment_.AdvanceClock(kSmallCPUQuantum);
796       TriggerMonitorAndWaitForCompletion();
797       EXPECT_EQ(2, hang_capture_count_);
798       EXPECT_EQ("Power suspended", seconds_since_last_power_resume_crash_key_);
799     }
800 
801     power_monitor_source.Resume();
802     constexpr TimeDelta kAfterResumeTime{base::Seconds(5)};
803     task_environment_.AdvanceClock(kAfterResumeTime);
804 
805     {
806       WatchHangsInScope expires_instantly(base::TimeDelta{});
807       TriggerMonitorAndWaitForCompletion();
808       EXPECT_EQ(3, hang_capture_count_);
809       EXPECT_EQ(base::NumberToString(kAfterResumeTime.InSeconds()),
810                 seconds_since_last_power_resume_crash_key_);
811     }
812   }
813 }
814 
815 namespace {
816 
817 // Determines how long the HangWatcher will wait between calls to
818 // Monitor(). Choose a low value so that that successive invocations happens
819 // fast. This makes tests that wait for monitoring run fast and makes tests that
820 // expect no monitoring fail fast.
821 const base::TimeDelta kMonitoringPeriod = base::Milliseconds(1);
822 
823 // Test if and how often the HangWatcher periodically monitors for hangs.
824 class HangWatcherPeriodicMonitoringTest : public testing::Test {
825  public:
HangWatcherPeriodicMonitoringTest()826   HangWatcherPeriodicMonitoringTest() {
827     hang_watcher_.InitializeOnMainThread(
828         HangWatcher::ProcessType::kBrowserProcess, false);
829 
830     hang_watcher_.SetMonitoringPeriodForTesting(kMonitoringPeriod);
831     hang_watcher_.SetOnHangClosureForTesting(base::BindRepeating(
832         &WaitableEvent::Signal, base::Unretained(&hang_event_)));
833 
834     // HangWatcher uses a TickClock to detect how long it slept in between calls
835     // to Monitor(). Override that clock to control its subjective passage of
836     // time.
837     hang_watcher_.SetTickClockForTesting(&test_clock_);
838   }
839 
840   HangWatcherPeriodicMonitoringTest(
841       const HangWatcherPeriodicMonitoringTest& other) = delete;
842   HangWatcherPeriodicMonitoringTest& operator=(
843       const HangWatcherPeriodicMonitoringTest& other) = delete;
844 
TearDown()845   void TearDown() override { hang_watcher_.UnitializeOnMainThreadForTesting(); }
846 
847  protected:
848   // Setup the callback invoked after waiting in HangWatcher to advance the
849   // tick clock by the desired time delta.
InstallAfterWaitCallback(base::TimeDelta time_delta)850   void InstallAfterWaitCallback(base::TimeDelta time_delta) {
851     hang_watcher_.SetAfterWaitCallbackForTesting(base::BindLambdaForTesting(
852         [this, time_delta](base::TimeTicks time_before_wait) {
853           test_clock_.Advance(time_delta);
854         }));
855   }
856 
857   base::SimpleTestTickClock test_clock_;
858 
859   // Single threaded to avoid ThreadPool WorkerThreads registering. Will run
860   // delayed tasks created by the tests.
861   test::SingleThreadTaskEnvironment task_environment_;
862 
863   std::unique_ptr<base::TickClock> fake_tick_clock_;
864   HangWatcher hang_watcher_;
865 
866   // Signaled when a hang is detected.
867   WaitableEvent hang_event_;
868 
869   base::ScopedClosureRunner unregister_thread_closure_;
870 };
871 }  // namespace
872 
873 // Don't register any threads for hang watching. HangWatcher should not monitor.
TEST_F(HangWatcherPeriodicMonitoringTest,NoPeriodicMonitoringWithoutRegisteredThreads)874 TEST_F(HangWatcherPeriodicMonitoringTest,
875        NoPeriodicMonitoringWithoutRegisteredThreads) {
876   RunLoop run_loop;
877 
878   // If a call to HangWatcher::Monitor() takes place the test will instantly
879   // fail.
880   hang_watcher_.SetAfterMonitorClosureForTesting(
881       base::BindLambdaForTesting([&run_loop]() {
882         ADD_FAILURE() << "Monitoring took place!";
883         run_loop.Quit();
884       }));
885 
886   // Make the HangWatcher tick clock advance by exactly the monitoring period
887   // after waiting so it will never detect oversleeping between attempts to call
888   // Monitor(). This would inhibit monitoring and make the test pass for the
889   // wrong reasons.
890   InstallAfterWaitCallback(kMonitoringPeriod);
891 
892   hang_watcher_.Start();
893 
894   // Unblock the test thread. No thread ever registered after the HangWatcher
895   // was created in the test's constructor. No monitoring should have taken
896   // place.
897   task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
898       FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
899   run_loop.Run();
900 
901   // NOTE:
902   // A lack of calls could technically also be caused by the HangWatcher thread
903   // executing too slowly / being descheduled. This is a known limitation.
904   // It's expected for |TestTimeouts::tiny_timeout()| to be large enough that
905   // this is rare.
906 }
907 
908 // During normal execution periodic monitorings should take place.
TEST_F(HangWatcherPeriodicMonitoringTest,PeriodicCallsTakePlace)909 TEST_F(HangWatcherPeriodicMonitoringTest, PeriodicCallsTakePlace) {
910   // HangWatcher::Monitor() will run once right away on thread registration.
911   // We want to make sure it runs at a couple more times from being scheduled.
912   constexpr int kMinimumMonitorCount = 3;
913 
914   RunLoop run_loop;
915 
916   // Setup the HangWatcher to unblock run_loop when the Monitor() has been
917   // invoked enough times.
918   hang_watcher_.SetAfterMonitorClosureForTesting(BarrierClosure(
919       kMinimumMonitorCount, base::BindLambdaForTesting([&run_loop]() {
920         // Test condition are confirmed, stop monitoring.
921         HangWatcher::StopMonitoringForTesting();
922 
923         // Unblock the test main thread.
924         run_loop.Quit();
925       })));
926 
927   // Make the HangWatcher tick clock advance by exactly the monitoring period
928   // after waiting so it will never detect oversleeping between attempts to call
929   // Monitor(). This would inhibit monitoring.
930   InstallAfterWaitCallback(kMonitoringPeriod);
931 
932   hang_watcher_.Start();
933 
934   // Register a thread,
935   unregister_thread_closure_ =
936       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
937 
938   run_loop.Run();
939 
940   // No monitored scope means no possible hangs.
941   ASSERT_FALSE(hang_event_.IsSignaled());
942 }
943 
944 // If the HangWatcher detects it slept for longer than expected it will not
945 // monitor.
TEST_F(HangWatcherPeriodicMonitoringTest,NoMonitorOnOverSleep)946 TEST_F(HangWatcherPeriodicMonitoringTest, NoMonitorOnOverSleep) {
947   RunLoop run_loop;
948 
949   // If a call to HangWatcher::Monitor() takes place the test will instantly
950   // fail.
951   hang_watcher_.SetAfterMonitorClosureForTesting(
952       base::BindLambdaForTesting([&run_loop]() {
953         ADD_FAILURE() << "Monitoring took place!";
954         run_loop.Quit();
955       }));
956 
957   // Make the HangWatcher tick clock advance so much after waiting that it will
958   // detect oversleeping every time. This will keep it from monitoring.
959   InstallAfterWaitCallback(base::Minutes(1));
960 
961   hang_watcher_.Start();
962 
963   // Register a thread.
964   unregister_thread_closure_ =
965       HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
966 
967   // Unblock the test thread. All waits were perceived as oversleeping so all
968   // monitoring was inhibited.
969   task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
970       FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
971   run_loop.Run();
972 
973   // NOTE: A lack of calls could technically also be caused by the HangWatcher
974   // thread executing too slowly / being descheduled. This is a known
975   // limitation. It's expected for |TestTimeouts::tiny_timeout()| to be large
976   // enough that this happens rarely.
977 }
978 
979 namespace {
980 class WatchHangsInScopeBlockingTest : public testing::Test {
981  public:
WatchHangsInScopeBlockingTest()982   WatchHangsInScopeBlockingTest() {
983     feature_list_.InitWithFeaturesAndParameters(kFeatureAndParams, {});
984     HangWatcher::InitializeOnMainThread(
985         HangWatcher::ProcessType::kBrowserProcess, false);
986 
987     hang_watcher_.SetOnHangClosureForTesting(base::BindLambdaForTesting([&] {
988       capture_started_.Signal();
989       // Simulate capturing that takes a long time.
990       PlatformThread::Sleep(base::Milliseconds(500));
991 
992       continue_capture_.Wait();
993       completed_capture_ = true;
994     }));
995 
996     hang_watcher_.SetAfterMonitorClosureForTesting(
997         base::BindLambdaForTesting([&] {
998           // Simulate monitoring that takes a long time.
999           PlatformThread::Sleep(base::Milliseconds(500));
1000           completed_monitoring_.Signal();
1001         }));
1002 
1003     // Make sure no periodic monitoring takes place.
1004     hang_watcher_.SetMonitoringPeriodForTesting(kVeryLongDelta);
1005 
1006     hang_watcher_.Start();
1007 
1008     // Register the test main thread for hang watching.
1009     unregister_thread_closure_ =
1010         HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
1011   }
1012 
TearDown()1013   void TearDown() override { HangWatcher::UnitializeOnMainThreadForTesting(); }
1014 
1015   WatchHangsInScopeBlockingTest(const WatchHangsInScopeBlockingTest& other) =
1016       delete;
1017   WatchHangsInScopeBlockingTest& operator=(
1018       const WatchHangsInScopeBlockingTest& other) = delete;
1019 
VerifyScopesDontBlock()1020   void VerifyScopesDontBlock() {
1021     // Start a WatchHangsInScope that cannot possibly cause a hang to be
1022     // detected.
1023     {
1024       WatchHangsInScope long_scope(kVeryLongDelta);
1025 
1026       // Manually trigger a monitoring.
1027       hang_watcher_.SignalMonitorEventForTesting();
1028 
1029       // Execution has to continue freely here as no capture is in progress.
1030     }
1031 
1032     // Monitoring should not be over yet because the test code should execute
1033     // faster when not blocked.
1034     EXPECT_FALSE(completed_monitoring_.IsSignaled());
1035 
1036     // Wait for the full monitoring process to be complete. This is to prove
1037     // that monitoring truly executed and that we raced the signaling.
1038     completed_monitoring_.Wait();
1039 
1040     // No hang means no capture.
1041     EXPECT_FALSE(completed_capture_);
1042   }
1043 
1044  protected:
1045   base::WaitableEvent capture_started_;
1046   base::WaitableEvent completed_monitoring_;
1047 
1048   // The HangWatcher waits on this event via the "on hang" closure when a hang
1049   // is detected.
1050   base::WaitableEvent continue_capture_;
1051   bool completed_capture_{false};
1052 
1053   base::test::ScopedFeatureList feature_list_;
1054   HangWatcher hang_watcher_;
1055   base::ScopedClosureRunner unregister_thread_closure_;
1056 };
1057 }  // namespace
1058 
1059 // Tests that execution is unimpeded by ~WatchHangsInScope() when no capture
1060 // ever takes place.
TEST_F(WatchHangsInScopeBlockingTest,ScopeDoesNotBlocksWithoutCapture)1061 TEST_F(WatchHangsInScopeBlockingTest, ScopeDoesNotBlocksWithoutCapture) {
1062   // No capture should take place so |continue_capture_| is not signaled to
1063   // create a test hang if one ever does.
1064   VerifyScopesDontBlock();
1065 }
1066 
1067 // Test that execution blocks in ~WatchHangsInScope() for a thread under
1068 // watch during the capturing of a hang.
TEST_F(WatchHangsInScopeBlockingTest,ScopeBlocksDuringCapture)1069 TEST_F(WatchHangsInScopeBlockingTest, ScopeBlocksDuringCapture) {
1070   // The capture completing is not dependent on any test event. Signal to make
1071   // sure the test is not blocked.
1072   continue_capture_.Signal();
1073 
1074   // Start a WatchHangsInScope that expires in the past already. Ensures
1075   // that the first monitor will detect a hang.
1076   {
1077     // Start a WatchHangsInScope that expires right away. Ensures that the
1078     // first monitor will detect a hang.
1079     WatchHangsInScope expires_right_away(base::TimeDelta{});
1080 
1081     // Manually trigger a monitoring.
1082     hang_watcher_.SignalMonitorEventForTesting();
1083 
1084     // Ensure that the hang capturing started.
1085     capture_started_.Wait();
1086 
1087     // Execution will get stuck in the outer scope because it can't escape
1088     // ~WatchHangsInScope() if a hang capture is under way.
1089   }
1090 
1091   // A hang was in progress so execution should have been blocked in
1092   // BlockWhileCaptureInProgress() until capture finishes.
1093   EXPECT_TRUE(completed_capture_);
1094   completed_monitoring_.Wait();
1095 
1096   // Reset expectations
1097   completed_monitoring_.Reset();
1098   capture_started_.Reset();
1099   completed_capture_ = false;
1100 
1101   // Verify that scopes don't block just because a capture happened in the past.
1102   VerifyScopesDontBlock();
1103 }
1104 
1105 #if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)
1106 // Flaky hangs on arm64 Macs: https://crbug.com/1140207
1107 #define MAYBE_NewScopeDoesNotBlockDuringCapture \
1108   DISABLED_NewScopeDoesNotBlockDuringCapture
1109 #else
1110 #define MAYBE_NewScopeDoesNotBlockDuringCapture \
1111   NewScopeDoesNotBlockDuringCapture
1112 #endif
1113 
1114 // Test that execution does not block in ~WatchHangsInScope() when the scope
1115 // was created after the start of a capture.
TEST_F(WatchHangsInScopeBlockingTest,MAYBE_NewScopeDoesNotBlockDuringCapture)1116 TEST_F(WatchHangsInScopeBlockingTest, MAYBE_NewScopeDoesNotBlockDuringCapture) {
1117   // Start a WatchHangsInScope that expires right away. Ensures that the
1118   // first monitor will detect a hang.
1119   WatchHangsInScope expires_right_away(base::TimeDelta{});
1120 
1121   // Manually trigger a monitoring.
1122   hang_watcher_.SignalMonitorEventForTesting();
1123 
1124   // Ensure that the hang capturing started.
1125   capture_started_.Wait();
1126 
1127   // A scope started once a capture is already under way should not block
1128   // execution.
1129   { WatchHangsInScope also_expires_right_away(base::TimeDelta{}); }
1130 
1131   // Wait for the new WatchHangsInScope to be destroyed to let the capture
1132   // finish. If the new scope block waiting for the capture to finish this would
1133   // create a deadlock and the test would hang.
1134   continue_capture_.Signal();
1135 }
1136 
1137 namespace internal {
1138 namespace {
1139 
1140 constexpr std::array<HangWatchDeadline::Flag, 3> kAllFlags{
1141     {HangWatchDeadline::Flag::kMinValue,
1142      HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope,
1143      HangWatchDeadline::Flag::kShouldBlockOnHang}};
1144 }  // namespace
1145 
1146 class HangWatchDeadlineTest : public testing::Test {
1147  protected:
AssertNoFlagsSet() const1148   void AssertNoFlagsSet() const {
1149     for (HangWatchDeadline::Flag flag : kAllFlags) {
1150       ASSERT_FALSE(deadline_.IsFlagSet(flag));
1151     }
1152   }
1153 
1154   // Return a flag mask without one of the flags for test purposes. Use to
1155   // ignore that effect of setting a flag that was just set.
FlagsMinus(uint64_t flags,HangWatchDeadline::Flag flag)1156   uint64_t FlagsMinus(uint64_t flags, HangWatchDeadline::Flag flag) {
1157     return flags & ~(static_cast<uint64_t>(flag));
1158   }
1159 
1160   HangWatchDeadline deadline_;
1161 };
1162 
1163 // Verify that the extract functions don't mangle any bits.
TEST_F(HangWatchDeadlineTest,BitsPreservedThroughExtract)1164 TEST_F(HangWatchDeadlineTest, BitsPreservedThroughExtract) {
1165   for (auto bits : {kAllOnes, kAllZeros, kOnesThenZeroes, kZeroesThenOnes}) {
1166     ASSERT_TRUE((HangWatchDeadline::ExtractFlags(bits) |
1167                  HangWatchDeadline::ExtractDeadline(bits)) == bits);
1168   }
1169 }
1170 
1171 // Verify that setting and clearing a persistent flag works and has no unwanted
1172 // side-effects. Neither the flags nor the deadline change concurrently in this
1173 // test.
TEST_F(HangWatchDeadlineTest,SetAndClearPersistentFlag)1174 TEST_F(HangWatchDeadlineTest, SetAndClearPersistentFlag) {
1175   AssertNoFlagsSet();
1176 
1177   // Grab the original values for flags and deadline.
1178   auto [old_flags, old_deadline] = deadline_.GetFlagsAndDeadline();
1179 
1180   // Set the flag. Operation cannot fail.
1181   deadline_.SetIgnoreCurrentWatchHangsInScope();
1182 
1183   // Get new flags and deadline.
1184   auto [new_flags, new_deadline] = deadline_.GetFlagsAndDeadline();
1185 
1186   // Flag was set properly.
1187   ASSERT_TRUE(HangWatchDeadline::IsFlagSet(
1188       HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope, new_flags));
1189 
1190   // No side-effect on deadline.
1191   ASSERT_EQ(new_deadline, old_deadline);
1192 
1193   // No side-effect on other flags.
1194   ASSERT_EQ(
1195       FlagsMinus(new_flags,
1196                  HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope),
1197       old_flags);
1198 
1199   // Clear the flag, operation cannot fail.
1200   deadline_.UnsetIgnoreCurrentWatchHangsInScope();
1201 
1202   // Update new values.
1203   std::tie(new_flags, new_deadline) = deadline_.GetFlagsAndDeadline();
1204 
1205   // All flags back to original state.
1206   ASSERT_EQ(new_flags, old_flags);
1207 
1208   // Deadline still unnafected.
1209   ASSERT_EQ(new_deadline, old_deadline);
1210 }
1211 
1212 // Verify setting the TimeTicks value works and has no unwanted side-effects.
TEST_F(HangWatchDeadlineTest,SetDeadline)1213 TEST_F(HangWatchDeadlineTest, SetDeadline) {
1214   TimeTicks ticks;
1215 
1216   AssertNoFlagsSet();
1217   ASSERT_NE(deadline_.GetDeadline(), ticks);
1218 
1219   // Set the deadline and verify it stuck.
1220   deadline_.SetDeadline(ticks);
1221   ASSERT_EQ(deadline_.GetDeadline(), ticks);
1222 
1223   // Only the value was modified, no flags should be set.
1224   AssertNoFlagsSet();
1225 }
1226 
1227 // Verify that setting a non-persistent flag (kShouldBlockOnHang)
1228 // when the TimeTicks value changed since calling the flag setting
1229 // function fails and has no side-effects.
TEST_F(HangWatchDeadlineTest,SetShouldBlockOnHangDeadlineChanged)1230 TEST_F(HangWatchDeadlineTest, SetShouldBlockOnHangDeadlineChanged) {
1231   AssertNoFlagsSet();
1232 
1233   auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
1234 
1235   // Simulate value change. Flags are constant.
1236   const base::TimeTicks new_deadline =
1237       base::TimeTicks::FromInternalValue(kArbitraryDeadline);
1238   ASSERT_NE(deadline, new_deadline);
1239   deadline_.SetSwitchBitsClosureForTesting(
1240       base::BindLambdaForTesting([]() { return kArbitraryDeadline; }));
1241 
1242   // kShouldBlockOnHangs does not persist through value change.
1243   ASSERT_FALSE(deadline_.SetShouldBlockOnHang(flags, deadline));
1244 
1245   // Flag was not applied.
1246   ASSERT_FALSE(
1247       deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
1248 
1249   // New value that was changed concurrently is preserved.
1250   ASSERT_EQ(deadline_.GetDeadline(), new_deadline);
1251 }
1252 
1253 // Verify that clearing a persistent (kIgnoreCurrentWatchHangsInScope) when
1254 // the value changed succeeds and has non side-effects.
TEST_F(HangWatchDeadlineTest,ClearIgnoreHangsDeadlineChanged)1255 TEST_F(HangWatchDeadlineTest, ClearIgnoreHangsDeadlineChanged) {
1256   AssertNoFlagsSet();
1257 
1258   auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
1259 
1260   deadline_.SetIgnoreCurrentWatchHangsInScope();
1261   std::tie(flags, deadline) = deadline_.GetFlagsAndDeadline();
1262   ASSERT_TRUE(HangWatchDeadline::IsFlagSet(
1263       HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope, flags));
1264 
1265   // Simulate deadline change. Flags are constant.
1266   const base::TimeTicks new_deadline =
1267       base::TimeTicks::FromInternalValue(kArbitraryDeadline);
1268   ASSERT_NE(deadline, new_deadline);
1269   deadline_.SetSwitchBitsClosureForTesting(base::BindLambdaForTesting([]() {
1270     return static_cast<uint64_t>(HangWatchDeadline::Flag::kShouldBlockOnHang) |
1271            kArbitraryDeadline;
1272   }));
1273 
1274   // Clearing kIgnoreHang is unaffected by deadline or flags change.
1275   deadline_.UnsetIgnoreCurrentWatchHangsInScope();
1276   ASSERT_FALSE(deadline_.IsFlagSet(
1277       HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
1278 
1279   // New deadline that was changed concurrently is preserved.
1280   ASSERT_TRUE(deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
1281   ASSERT_EQ(deadline_.GetDeadline(), new_deadline);
1282 }
1283 
1284 // Verify that setting a persistent (kIgnoreCurrentWatchHangsInScope) when
1285 // the deadline or flags changed succeeds and has non side-effects.
TEST_F(HangWatchDeadlineTest,SetIgnoreCurrentHangWatchScopeEnableDeadlineChangedd)1286 TEST_F(HangWatchDeadlineTest,
1287        SetIgnoreCurrentHangWatchScopeEnableDeadlineChangedd) {
1288   AssertNoFlagsSet();
1289 
1290   auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
1291 
1292   // Simulate deadline change. Flags are constant.
1293   const base::TimeTicks new_deadline =
1294       base::TimeTicks::FromInternalValue(kArbitraryDeadline);
1295 
1296   ASSERT_NE(deadline, new_deadline);
1297   deadline_.SetSwitchBitsClosureForTesting(base::BindLambdaForTesting([]() {
1298     return static_cast<uint64_t>(HangWatchDeadline::Flag::kShouldBlockOnHang) |
1299            kArbitraryDeadline;
1300   }));
1301 
1302   // kIgnoreHang persists through value change.
1303   deadline_.SetIgnoreCurrentWatchHangsInScope();
1304   ASSERT_TRUE(deadline_.IsFlagSet(
1305       HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
1306 
1307   // New deadline and flags that changed concurrently are preserved.
1308   ASSERT_TRUE(deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
1309   ASSERT_EQ(deadline_.GetDeadline(), new_deadline);
1310 }
1311 
1312 // Setting a new deadline should wipe flags that a not persistent.
1313 // Persistent flags should not be disturbed.
TEST_F(HangWatchDeadlineTest,SetDeadlineWipesFlags)1314 TEST_F(HangWatchDeadlineTest, SetDeadlineWipesFlags) {
1315   auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
1316 
1317   ASSERT_TRUE(deadline_.SetShouldBlockOnHang(flags, deadline));
1318   ASSERT_TRUE(deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
1319 
1320   std::tie(flags, deadline) = deadline_.GetFlagsAndDeadline();
1321 
1322   deadline_.SetIgnoreCurrentWatchHangsInScope();
1323   ASSERT_TRUE(deadline_.IsFlagSet(
1324       HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
1325 
1326   // Change the deadline.
1327   deadline_.SetDeadline(TimeTicks{});
1328   ASSERT_EQ(deadline_.GetDeadline(), TimeTicks{});
1329 
1330   // Verify the persistent flag stuck and the non-persistent one was unset.
1331   ASSERT_FALSE(
1332       deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
1333   ASSERT_TRUE(deadline_.IsFlagSet(
1334       HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
1335 }
1336 
1337 }  // namespace internal
1338 
1339 }  // namespace base
1340