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