xref: /aosp_15_r20/external/perfetto/src/base/watchdog_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/watchdog.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
20*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/thread_utils.h"
21*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/paged_memory.h"
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/scoped_file.h"
23*6dbdd20aSAndroid Build Coastguard Worker #include "test/gtest_and_gmock.h"
24*6dbdd20aSAndroid Build Coastguard Worker 
25*6dbdd20aSAndroid Build Coastguard Worker #include <signal.h>
26*6dbdd20aSAndroid Build Coastguard Worker #include <time.h>
27*6dbdd20aSAndroid Build Coastguard Worker 
28*6dbdd20aSAndroid Build Coastguard Worker #include <condition_variable>
29*6dbdd20aSAndroid Build Coastguard Worker #include <map>
30*6dbdd20aSAndroid Build Coastguard Worker #include <memory>
31*6dbdd20aSAndroid Build Coastguard Worker #include <mutex>
32*6dbdd20aSAndroid Build Coastguard Worker #include <thread>
33*6dbdd20aSAndroid Build Coastguard Worker #include <vector>
34*6dbdd20aSAndroid Build Coastguard Worker 
35*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
36*6dbdd20aSAndroid Build Coastguard Worker namespace base {
37*6dbdd20aSAndroid Build Coastguard Worker namespace {
38*6dbdd20aSAndroid Build Coastguard Worker 
39*6dbdd20aSAndroid Build Coastguard Worker static auto kCrashReasonIgnored = WatchdogCrashReason::kUnspecified;
40*6dbdd20aSAndroid Build Coastguard Worker 
41*6dbdd20aSAndroid Build Coastguard Worker class TestWatchdog : public Watchdog {
42*6dbdd20aSAndroid Build Coastguard Worker  public:
TestWatchdog(uint32_t polling_interval_ms)43*6dbdd20aSAndroid Build Coastguard Worker   explicit TestWatchdog(uint32_t polling_interval_ms)
44*6dbdd20aSAndroid Build Coastguard Worker       : Watchdog(polling_interval_ms) {
45*6dbdd20aSAndroid Build Coastguard Worker     disable_kill_failsafe_for_testing_ = true;
46*6dbdd20aSAndroid Build Coastguard Worker   }
~TestWatchdog()47*6dbdd20aSAndroid Build Coastguard Worker   ~TestWatchdog() override {}
48*6dbdd20aSAndroid Build Coastguard Worker };
49*6dbdd20aSAndroid Build Coastguard Worker 
TEST(WatchdogTest,NoTimerCrashIfNotEnabled)50*6dbdd20aSAndroid Build Coastguard Worker TEST(WatchdogTest, NoTimerCrashIfNotEnabled) {
51*6dbdd20aSAndroid Build Coastguard Worker   // CreateFatalTimer should be a noop if the watchdog is not enabled.
52*6dbdd20aSAndroid Build Coastguard Worker   TestWatchdog watchdog(100);
53*6dbdd20aSAndroid Build Coastguard Worker   auto handle = watchdog.CreateFatalTimer(1, kCrashReasonIgnored);
54*6dbdd20aSAndroid Build Coastguard Worker   usleep(100 * 1000);
55*6dbdd20aSAndroid Build Coastguard Worker }
56*6dbdd20aSAndroid Build Coastguard Worker 
TEST(WatchdogTest,TimerCrash)57*6dbdd20aSAndroid Build Coastguard Worker TEST(WatchdogTest, TimerCrash) {
58*6dbdd20aSAndroid Build Coastguard Worker   // Create a timer for 20 ms and don't release wihin the time.
59*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_DEATH(
60*6dbdd20aSAndroid Build Coastguard Worker       {
61*6dbdd20aSAndroid Build Coastguard Worker         TestWatchdog watchdog(100);
62*6dbdd20aSAndroid Build Coastguard Worker         watchdog.Start();
63*6dbdd20aSAndroid Build Coastguard Worker         auto handle = watchdog.CreateFatalTimer(20, kCrashReasonIgnored);
64*6dbdd20aSAndroid Build Coastguard Worker         usleep(200 * 1000);
65*6dbdd20aSAndroid Build Coastguard Worker       },
66*6dbdd20aSAndroid Build Coastguard Worker       "");
67*6dbdd20aSAndroid Build Coastguard Worker }
68*6dbdd20aSAndroid Build Coastguard Worker 
TEST(WatchdogTest,CrashEvenWhenMove)69*6dbdd20aSAndroid Build Coastguard Worker TEST(WatchdogTest, CrashEvenWhenMove) {
70*6dbdd20aSAndroid Build Coastguard Worker   std::map<int, Watchdog::Timer> timers;
71*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_DEATH(
72*6dbdd20aSAndroid Build Coastguard Worker       {
73*6dbdd20aSAndroid Build Coastguard Worker         TestWatchdog watchdog(100);
74*6dbdd20aSAndroid Build Coastguard Worker         watchdog.Start();
75*6dbdd20aSAndroid Build Coastguard Worker         timers.emplace(0, watchdog.CreateFatalTimer(20, kCrashReasonIgnored));
76*6dbdd20aSAndroid Build Coastguard Worker         usleep(200 * 1000);
77*6dbdd20aSAndroid Build Coastguard Worker       },
78*6dbdd20aSAndroid Build Coastguard Worker       "");
79*6dbdd20aSAndroid Build Coastguard Worker }
80*6dbdd20aSAndroid Build Coastguard Worker 
TEST(WatchdogTest,CrashMemory)81*6dbdd20aSAndroid Build Coastguard Worker TEST(WatchdogTest, CrashMemory) {
82*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_DEATH(
83*6dbdd20aSAndroid Build Coastguard Worker       {
84*6dbdd20aSAndroid Build Coastguard Worker         // Allocate 8MB of data and use it to increase RSS.
85*6dbdd20aSAndroid Build Coastguard Worker         const size_t kSize = 8 * 1024 * 1024;
86*6dbdd20aSAndroid Build Coastguard Worker         auto void_ptr = PagedMemory::Allocate(kSize);
87*6dbdd20aSAndroid Build Coastguard Worker         volatile uint8_t* ptr = static_cast<volatile uint8_t*>(void_ptr.Get());
88*6dbdd20aSAndroid Build Coastguard Worker         for (size_t i = 0; i < kSize; i += sizeof(size_t)) {
89*6dbdd20aSAndroid Build Coastguard Worker           *reinterpret_cast<volatile size_t*>(&ptr[i]) = i;
90*6dbdd20aSAndroid Build Coastguard Worker         }
91*6dbdd20aSAndroid Build Coastguard Worker 
92*6dbdd20aSAndroid Build Coastguard Worker         TestWatchdog watchdog(5);
93*6dbdd20aSAndroid Build Coastguard Worker         watchdog.SetMemoryLimit(8 * 1024 * 1024, 25);
94*6dbdd20aSAndroid Build Coastguard Worker         watchdog.Start();
95*6dbdd20aSAndroid Build Coastguard Worker 
96*6dbdd20aSAndroid Build Coastguard Worker         // Sleep so that the watchdog has some time to pick it up.
97*6dbdd20aSAndroid Build Coastguard Worker         usleep(1000 * 1000);
98*6dbdd20aSAndroid Build Coastguard Worker       },
99*6dbdd20aSAndroid Build Coastguard Worker       "");
100*6dbdd20aSAndroid Build Coastguard Worker }
101*6dbdd20aSAndroid Build Coastguard Worker 
TEST(WatchdogTest,CrashCpu)102*6dbdd20aSAndroid Build Coastguard Worker TEST(WatchdogTest, CrashCpu) {
103*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_DEATH(
104*6dbdd20aSAndroid Build Coastguard Worker       {
105*6dbdd20aSAndroid Build Coastguard Worker         TestWatchdog watchdog(1);
106*6dbdd20aSAndroid Build Coastguard Worker         watchdog.SetCpuLimit(10, 25);
107*6dbdd20aSAndroid Build Coastguard Worker         watchdog.Start();
108*6dbdd20aSAndroid Build Coastguard Worker         volatile int x = 0;
109*6dbdd20aSAndroid Build Coastguard Worker         for (;;) {
110*6dbdd20aSAndroid Build Coastguard Worker           x++;
111*6dbdd20aSAndroid Build Coastguard Worker         }
112*6dbdd20aSAndroid Build Coastguard Worker       },
113*6dbdd20aSAndroid Build Coastguard Worker       "");
114*6dbdd20aSAndroid Build Coastguard Worker }
115*6dbdd20aSAndroid Build Coastguard Worker 
116*6dbdd20aSAndroid Build Coastguard Worker // The test below tests that the fatal timer signal is sent to the thread that
117*6dbdd20aSAndroid Build Coastguard Worker // created the timer and not a random one.
118*6dbdd20aSAndroid Build Coastguard Worker 
RestoreSIGABRT(const struct sigaction * act)119*6dbdd20aSAndroid Build Coastguard Worker int RestoreSIGABRT(const struct sigaction* act) {
120*6dbdd20aSAndroid Build Coastguard Worker   return sigaction(SIGABRT, act, nullptr);
121*6dbdd20aSAndroid Build Coastguard Worker }
122*6dbdd20aSAndroid Build Coastguard Worker 
123*6dbdd20aSAndroid Build Coastguard Worker PlatformThreadId g_aborted_thread = 0;
SIGABRTHandler(int)124*6dbdd20aSAndroid Build Coastguard Worker void SIGABRTHandler(int) {
125*6dbdd20aSAndroid Build Coastguard Worker   g_aborted_thread = GetThreadId();
126*6dbdd20aSAndroid Build Coastguard Worker }
127*6dbdd20aSAndroid Build Coastguard Worker 
TEST(WatchdogTest,TimerCrashDeliveredToCallerThread)128*6dbdd20aSAndroid Build Coastguard Worker TEST(WatchdogTest, TimerCrashDeliveredToCallerThread) {
129*6dbdd20aSAndroid Build Coastguard Worker   // Setup a signal handler so that SIGABRT doesn't cause a crash but just
130*6dbdd20aSAndroid Build Coastguard Worker   // records the current thread id.
131*6dbdd20aSAndroid Build Coastguard Worker   struct sigaction oldact;
132*6dbdd20aSAndroid Build Coastguard Worker   struct sigaction newact = {};
133*6dbdd20aSAndroid Build Coastguard Worker   newact.sa_handler = SIGABRTHandler;
134*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(sigaction(SIGABRT, &newact, &oldact), 0);
135*6dbdd20aSAndroid Build Coastguard Worker   base::ScopedResource<const struct sigaction*, RestoreSIGABRT, nullptr>
136*6dbdd20aSAndroid Build Coastguard Worker       auto_restore(&oldact);
137*6dbdd20aSAndroid Build Coastguard Worker 
138*6dbdd20aSAndroid Build Coastguard Worker   // Create 8 threads. All of them but one will just sleep. The selected one
139*6dbdd20aSAndroid Build Coastguard Worker   // will register a watchdog and fail.
140*6dbdd20aSAndroid Build Coastguard Worker   const size_t kKillThreadNum = 3;
141*6dbdd20aSAndroid Build Coastguard Worker   std::mutex mutex;
142*6dbdd20aSAndroid Build Coastguard Worker   std::condition_variable cv;
143*6dbdd20aSAndroid Build Coastguard Worker   bool quit = false;
144*6dbdd20aSAndroid Build Coastguard Worker   g_aborted_thread = 0;
145*6dbdd20aSAndroid Build Coastguard Worker   PlatformThreadId expected_tid = 0;
146*6dbdd20aSAndroid Build Coastguard Worker 
147*6dbdd20aSAndroid Build Coastguard Worker   auto thread_fn = [&mutex, &cv, &quit, &expected_tid](size_t thread_num) {
148*6dbdd20aSAndroid Build Coastguard Worker     if (thread_num == kKillThreadNum) {
149*6dbdd20aSAndroid Build Coastguard Worker       expected_tid = GetThreadId();
150*6dbdd20aSAndroid Build Coastguard Worker       TestWatchdog watchdog(100);
151*6dbdd20aSAndroid Build Coastguard Worker       watchdog.Start();
152*6dbdd20aSAndroid Build Coastguard Worker       auto handle = watchdog.CreateFatalTimer(2, kCrashReasonIgnored);
153*6dbdd20aSAndroid Build Coastguard Worker       usleep(200 * 1000);  // This will be interrupted by the fatal timer.
154*6dbdd20aSAndroid Build Coastguard Worker       std::unique_lock<std::mutex> lock(mutex);
155*6dbdd20aSAndroid Build Coastguard Worker       quit = true;
156*6dbdd20aSAndroid Build Coastguard Worker       cv.notify_all();
157*6dbdd20aSAndroid Build Coastguard Worker     } else {
158*6dbdd20aSAndroid Build Coastguard Worker       std::unique_lock<std::mutex> lock(mutex);
159*6dbdd20aSAndroid Build Coastguard Worker       cv.wait(lock, [&quit] { return quit; });
160*6dbdd20aSAndroid Build Coastguard Worker     }
161*6dbdd20aSAndroid Build Coastguard Worker   };
162*6dbdd20aSAndroid Build Coastguard Worker 
163*6dbdd20aSAndroid Build Coastguard Worker   std::vector<std::thread> threads;
164*6dbdd20aSAndroid Build Coastguard Worker 
165*6dbdd20aSAndroid Build Coastguard Worker   for (size_t i = 0; i < 8; i++)
166*6dbdd20aSAndroid Build Coastguard Worker     threads.emplace_back(thread_fn, i);
167*6dbdd20aSAndroid Build Coastguard Worker 
168*6dbdd20aSAndroid Build Coastguard Worker   // Join them all.
169*6dbdd20aSAndroid Build Coastguard Worker   for (auto& thread : threads)
170*6dbdd20aSAndroid Build Coastguard Worker     thread.join();
171*6dbdd20aSAndroid Build Coastguard Worker 
172*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(g_aborted_thread, expected_tid);
173*6dbdd20aSAndroid Build Coastguard Worker }
174*6dbdd20aSAndroid Build Coastguard Worker 
175*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
176*6dbdd20aSAndroid Build Coastguard Worker }  // namespace base
177*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
178