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