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