1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <chrono>
17 #include <condition_variable>
18 #include <filesystem>
19 #include <mutex>
20 #include <string>
21 #include <thread>
22 
23 #include <android-base/file.h>
24 #include <android-base/logging.h>
25 #include <bpf/BpfUtils.h>
26 #include <gtest/gtest.h>
27 #include <poll.h>
28 #include <signal.h>
29 #include <string.h>
30 #include <sys/mman.h>
31 #include <sys/sysinfo.h>
32 #include <unistd.h>
33 
34 #include <BpfSyscallWrappers.h>
35 
36 #include <memevents/memevents.h>
37 #include <memevents/memevents_test.h>
38 
39 using namespace ::android::base;
40 using namespace ::android::bpf::memevents;
41 
42 using android::bpf::isAtLeastKernelVersion;
43 
44 namespace fs = std::filesystem;
45 
46 static const MemEventClient mem_test_client = MemEventClient::TEST_CLIENT;
47 static const int page_size = getpagesize();
48 static const bool isBpfRingBufferSupported = isAtLeastKernelVersion(5, 8, 0);
49 static const std::string bpfRbsPaths[MemEventClient::NR_CLIENTS] = {
50         MEM_EVENTS_AMS_RB, MEM_EVENTS_LMKD_RB, MEM_EVENTS_TEST_RB};
51 static const std::string testBpfSkfilterProgPaths[NR_MEM_EVENTS] = {
52         MEM_EVENTS_TEST_OOM_KILL_TP, MEM_EVENTS_TEST_DIRECT_RECLAIM_START_TP,
53         MEM_EVENTS_TEST_DIRECT_RECLAIM_END_TP, MEM_EVENTS_TEST_KSWAPD_WAKE_TP,
54         MEM_EVENTS_TEST_KSWAPD_SLEEP_TP};
55 static const std::filesystem::path sysrq_trigger_path = "proc/sysrq-trigger";
56 
initializeTestListener(std::unique_ptr<MemEventListener> & memevent_listener,const bool attachTpForTests)57 static void initializeTestListener(std::unique_ptr<MemEventListener>& memevent_listener,
58                                    const bool attachTpForTests) {
59     if (!memevent_listener) {
60         memevent_listener = std::make_unique<MemEventListener>(mem_test_client, attachTpForTests);
61     }
62     ASSERT_TRUE(memevent_listener) << "Memory event listener is not initialized";
63 
64     /*
65      * Some test suite seems to have issues when trying to re-initialize
66      * the BPF manager for the MemEventsTest, therefore we retry.
67      */
68     if (!memevent_listener->ok()) {
69         memevent_listener.reset();
70         /* This sleep is needed in order to allow for the BPF manager to
71          * initialize without failure.
72          */
73         sleep(1);
74         memevent_listener = std::make_unique<MemEventListener>(mem_test_client);
75     }
76     ASSERT_TRUE(memevent_listener->ok()) << "BPF ring buffer manager didn't initialize";
77 }
78 
79 /*
80  * Test suite to test on devices that don't support BPF, kernel <= 5.8.
81  * We allow for the listener to iniailize gracefully, but every public API will
82  * return false/fail.
83  */
84 class MemEventListenerUnsupportedKernel : public ::testing::Test {
85   protected:
86     std::unique_ptr<MemEventListener> memevent_listener;
87 
SetUpTestSuite()88     static void SetUpTestSuite() {
89         if (isBpfRingBufferSupported) {
90             GTEST_SKIP()
91                     << "BPF ring buffers is supported on this kernel, running alternative tests";
92         }
93     }
94 
SetUp()95     void SetUp() override { initializeTestListener(memevent_listener, false); }
96 
TearDown()97     void TearDown() override { memevent_listener.reset(); }
98 };
99 
100 /*
101  * Listener shouldn't fail when initializing on a kernel that doesn't support BPF.
102  */
TEST_F(MemEventListenerUnsupportedKernel,initialize_invalid_client)103 TEST_F(MemEventListenerUnsupportedKernel, initialize_invalid_client) {
104     std::unique_ptr<MemEventListener> listener =
105             std::make_unique<MemEventListener>(MemEventClient::AMS);
106     ASSERT_TRUE(listener) << "Failed to initialize listener on older kernel";
107 }
108 
109 /*
110  * Register will fail when running on a older kernel, even when we pass a valid event type.
111  */
TEST_F(MemEventListenerUnsupportedKernel,fail_to_register)112 TEST_F(MemEventListenerUnsupportedKernel, fail_to_register) {
113     ASSERT_FALSE(memevent_listener->registerEvent(MEM_EVENT_OOM_KILL))
114             << "Listener should fail to register valid event type on an unsupported kernel";
115     ASSERT_FALSE(memevent_listener->registerEvent(NR_MEM_EVENTS))
116             << "Listener should fail to register invalid event type";
117 }
118 
119 /*
120  * Listen will fail when running on a older kernel.
121  * The listen() function always checks first if we are running on an older kernel,
122  * therefore we don't need to register for an event before trying to call listen.
123  */
TEST_F(MemEventListenerUnsupportedKernel,fail_to_listen)124 TEST_F(MemEventListenerUnsupportedKernel, fail_to_listen) {
125     ASSERT_FALSE(memevent_listener->listen()) << "listen() should fail on unsupported kernel";
126 }
127 
128 /*
129  * Just like the other APIs, deregister will return false immediately on an older
130  * kernel.
131  */
TEST_F(MemEventListenerUnsupportedKernel,fail_to_unregister_event)132 TEST_F(MemEventListenerUnsupportedKernel, fail_to_unregister_event) {
133     ASSERT_FALSE(memevent_listener->deregisterEvent(MEM_EVENT_OOM_KILL))
134             << "Listener should fail to deregister valid event type on an older kernel";
135     ASSERT_FALSE(memevent_listener->deregisterEvent(NR_MEM_EVENTS))
136             << "Listener should fail to deregister invalid event type, regardless of kernel "
137                "version";
138 }
139 
140 /*
141  * The `getMemEvents()` API should fail on an older kernel.
142  */
TEST_F(MemEventListenerUnsupportedKernel,fail_to_get_mem_events)143 TEST_F(MemEventListenerUnsupportedKernel, fail_to_get_mem_events) {
144     std::vector<mem_event_t> mem_events;
145     ASSERT_FALSE(memevent_listener->getMemEvents(mem_events))
146             << "Fetching memory events should fail on an older kernel";
147 }
148 
149 /*
150  * The `getRingBufferFd()` API should fail on an older kernel
151  */
TEST_F(MemEventListenerUnsupportedKernel,fail_to_get_rb_fd)152 TEST_F(MemEventListenerUnsupportedKernel, fail_to_get_rb_fd) {
153     ASSERT_LT(memevent_listener->getRingBufferFd(), 0)
154             << "Fetching bpf-rb file descriptor should fail on an older kernel";
155 }
156 
157 /*
158  * Test suite verifies that all the BPF programs and ring buffers are loaded.
159  */
160 class MemEventsBpfSetupTest : public ::testing::Test {
161   protected:
SetUpTestSuite()162     static void SetUpTestSuite() {
163         if (!isBpfRingBufferSupported) {
164             GTEST_SKIP() << "BPF ring buffers not supported in kernels below 5.8";
165         }
166     }
167 };
168 
169 /*
170  * Verify that all the ams bpf-programs are loaded.
171  */
TEST_F(MemEventsBpfSetupTest,loaded_ams_progs)172 TEST_F(MemEventsBpfSetupTest, loaded_ams_progs) {
173     ASSERT_TRUE(std::filesystem::exists(MEM_EVENTS_AMS_OOM_MARK_VICTIM_TP))
174             << "Failed to find ams mark_victim bpf-program";
175 }
176 
177 /*
178  * Verify that all the lmkd bpf-programs are loaded.
179  */
TEST_F(MemEventsBpfSetupTest,loaded_lmkd_progs)180 TEST_F(MemEventsBpfSetupTest, loaded_lmkd_progs) {
181     ASSERT_TRUE(std::filesystem::exists(MEM_EVENTS_LMKD_VMSCAN_DR_BEGIN_TP))
182             << "Failed to find lmkd direct_reclaim_begin bpf-program";
183     ASSERT_TRUE(std::filesystem::exists(MEM_EVENTS_LMKD_VMSCAN_DR_END_TP))
184             << "Failed to find lmkd direct_reclaim_end bpf-program";
185     ASSERT_TRUE(std::filesystem::exists(MEM_EVENTS_LMKD_VMSCAN_KSWAPD_WAKE_TP))
186             << "Failed to find lmkd kswapd_wake bpf-program";
187     ASSERT_TRUE(std::filesystem::exists(MEM_EVENTS_LMKD_VMSCAN_KSWAPD_SLEEP_TP))
188             << "Failed to find lmkd kswapd_sleep bpf-program";
189 }
190 
191 /*
192  * Verify that all the memevents test bpf-skfilter-programs are loaded.
193  */
TEST_F(MemEventsBpfSetupTest,loaded_test_skfilter_progs)194 TEST_F(MemEventsBpfSetupTest, loaded_test_skfilter_progs) {
195     for (int i = 0; i < NR_MEM_EVENTS; i++) {
196         ASSERT_TRUE(std::filesystem::exists(testBpfSkfilterProgPaths[i]))
197                 << "Failed to find testing bpf-prog: " << testBpfSkfilterProgPaths[i];
198     }
199 }
200 
201 /*
202  * Verify that all [bpf] ring buffer's are loaded.
203  * We expect to have at least 1 ring buffer for each client in `MemEventClient`.
204  */
TEST_F(MemEventsBpfSetupTest,loaded_ring_buffers)205 TEST_F(MemEventsBpfSetupTest, loaded_ring_buffers) {
206     for (int i = 0; i < MemEventClient::NR_CLIENTS; i++) {
207         ASSERT_TRUE(std::filesystem::exists(bpfRbsPaths[i]))
208                 << "Failed to find bpf ring-buffer: " << bpfRbsPaths[i];
209     }
210 }
211 
212 class MemEventsListenerTest : public ::testing::Test {
213   protected:
214     std::unique_ptr<MemEventListener> memevent_listener;
215 
SetUpTestSuite()216     static void SetUpTestSuite() {
217         if (!isBpfRingBufferSupported) {
218             GTEST_SKIP() << "BPF ring buffers not supported in kernels below 5.8";
219         }
220     }
221 
SetUp()222     void SetUp() override { initializeTestListener(memevent_listener, false); }
223 
TearDown()224     void TearDown() override { memevent_listener.reset(); }
225 };
226 
227 /*
228  * MemEventListener should fail, through a `std::abort()`, when attempted to initialize
229  * with an invalid `MemEventClient`. By passing `MemEventClient::NR_CLIENTS`, and attempting
230  * to convert/pass `-1` as a client, we expect the listener initialization to fail.
231  */
TEST_F(MemEventsListenerTest,initialize_invalid_client)232 TEST_F(MemEventsListenerTest, initialize_invalid_client) {
233     EXPECT_DEATH(MemEventListener listener(MemEventClient::NR_CLIENTS), "");
234     EXPECT_DEATH(MemEventListener listener(static_cast<MemEventClient>(-1)), "");
235 }
236 
237 /*
238  * MemEventListener should fail when a valid, non-testing, client tries to initialize
239  * by passing the optional test flag.
240  */
TEST_F(MemEventsListenerTest,initialize_valid_client_with_test_flag)241 TEST_F(MemEventsListenerTest, initialize_valid_client_with_test_flag) {
242     for (int i = 0; i < MemEventClient::TEST_CLIENT; i++) {
243         const MemEventClient valid_client = static_cast<MemEventClient>(i);
244         EXPECT_DEATH(MemEventListener listener(valid_client, true), "")
245                 << "Only test client is allowed to set the test flag to true";
246     }
247 }
248 
249 /*
250  * MemEventClient base client should equal to AMS client.
251  */
TEST_F(MemEventsListenerTest,base_client_equal_ams_client)252 TEST_F(MemEventsListenerTest, base_client_equal_ams_client) {
253     ASSERT_EQ(static_cast<int>(MemEventClient::BASE), static_cast<int>(MemEventClient::AMS))
254             << "Base client should be equal to AMS client";
255 }
256 
257 /*
258  * Validate `registerEvent()` fails with values >= `NR_MEM_EVENTS`.
259  */
TEST_F(MemEventsListenerTest,register_event_invalid_values)260 TEST_F(MemEventsListenerTest, register_event_invalid_values) {
261     ASSERT_FALSE(memevent_listener->registerEvent(NR_MEM_EVENTS));
262     ASSERT_FALSE(memevent_listener->registerEvent(NR_MEM_EVENTS + 1));
263     ASSERT_FALSE(memevent_listener->registerEvent(-1));
264 }
265 
266 /*
267  * Validate that `registerEvent()` always returns true when we try registering
268  * the same [valid] event/value.
269  */
TEST_F(MemEventsListenerTest,register_event_repeated_event)270 TEST_F(MemEventsListenerTest, register_event_repeated_event) {
271     const int event_type = MEM_EVENT_OOM_KILL;
272     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
273     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
274     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
275 }
276 
277 /*
278  * Validate that `registerEvent()` is able to register all the `MEM_EVENT_*` values
279  * from `bpf_types.h`.
280  */
TEST_F(MemEventsListenerTest,register_event_valid_values)281 TEST_F(MemEventsListenerTest, register_event_valid_values) {
282     for (unsigned int i = 0; i < NR_MEM_EVENTS; i++)
283         ASSERT_TRUE(memevent_listener->registerEvent(i)) << "Failed to register event: " << i;
284 }
285 
286 /*
287  * `listen()` should return false when no events have been registered.
288  */
TEST_F(MemEventsListenerTest,listen_no_registered_events)289 TEST_F(MemEventsListenerTest, listen_no_registered_events) {
290     ASSERT_FALSE(memevent_listener->listen());
291 }
292 
293 /*
294  * Validate `deregisterEvent()` fails with values >= `NR_MEM_EVENTS`.
295  * Exactly like `register_event_invalid_values` test.
296  */
TEST_F(MemEventsListenerTest,deregister_event_invalid_values)297 TEST_F(MemEventsListenerTest, deregister_event_invalid_values) {
298     ASSERT_FALSE(memevent_listener->deregisterEvent(NR_MEM_EVENTS));
299     ASSERT_FALSE(memevent_listener->deregisterEvent(NR_MEM_EVENTS + 1));
300     ASSERT_FALSE(memevent_listener->deregisterEvent(-1));
301 }
302 
303 /*
304  * Validate that `deregisterEvent()` always returns true when we try
305  * deregistering the same [valid] event/value.
306  */
TEST_F(MemEventsListenerTest,deregister_repeated_event)307 TEST_F(MemEventsListenerTest, deregister_repeated_event) {
308     const int event_type = MEM_EVENT_DIRECT_RECLAIM_BEGIN;
309     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
310     ASSERT_TRUE(memevent_listener->deregisterEvent(event_type));
311     ASSERT_TRUE(memevent_listener->deregisterEvent(event_type));
312 }
313 
314 /*
315  * Verify that the `deregisterEvent()` will return true
316  * when we deregister a non-registered, valid, event.
317  */
TEST_F(MemEventsListenerTest,deregister_unregistered_event)318 TEST_F(MemEventsListenerTest, deregister_unregistered_event) {
319     ASSERT_TRUE(memevent_listener->deregisterEvent(MEM_EVENT_DIRECT_RECLAIM_END));
320 }
321 
322 /*
323  * Validate that the `deregisterAllEvents()` closes all the registered
324  * events.
325  */
TEST_F(MemEventsListenerTest,deregister_all_events)326 TEST_F(MemEventsListenerTest, deregister_all_events) {
327     ASSERT_TRUE(memevent_listener->registerEvent(MEM_EVENT_OOM_KILL));
328     ASSERT_TRUE(memevent_listener->registerEvent(MEM_EVENT_DIRECT_RECLAIM_BEGIN));
329     memevent_listener->deregisterAllEvents();
330     ASSERT_FALSE(memevent_listener->listen())
331             << "Expected to fail since we are not registered to any events";
332 }
333 
334 /*
335  * Validating that `MEM_EVENT_BASE` is equal to `MEM_EVENT_OOM_KILL`.
336  */
TEST_F(MemEventsListenerTest,base_and_oom_events_are_equal)337 TEST_F(MemEventsListenerTest, base_and_oom_events_are_equal) {
338     ASSERT_EQ(MEM_EVENT_OOM_KILL, MEM_EVENT_BASE)
339             << "MEM_EVENT_BASE should be equal to MEM_EVENT_OOM_KILL";
340 }
341 
342 /*
343  * Validate that `getRingBufferFd()` returns a valid file descriptor.
344  */
TEST_F(MemEventsListenerTest,get_client_rb_fd)345 TEST_F(MemEventsListenerTest, get_client_rb_fd) {
346     ASSERT_GE(memevent_listener->getRingBufferFd(), 0)
347             << "Failed to get a valid bpf-rb file descriptor";
348 }
349 
350 class MemEventsListenerBpf : public ::testing::Test {
351   private:
352     android::base::unique_fd mProgram;
353 
setUpProgram(unsigned int event_type)354     void setUpProgram(unsigned int event_type) {
355         ASSERT_TRUE(event_type < NR_MEM_EVENTS) << "Invalid event type provided";
356 
357         int bpf_fd = android::bpf::retrieveProgram(testBpfSkfilterProgPaths[event_type].c_str());
358         ASSERT_NE(bpf_fd, -1) << "Retrieve bpf program failed with prog path: "
359                               << testBpfSkfilterProgPaths[event_type];
360         mProgram.reset(bpf_fd);
361 
362         ASSERT_GE(mProgram.get(), 0)
363                 << testBpfSkfilterProgPaths[event_type] << " was either not found or inaccessible.";
364     }
365 
366     /*
367      * Always call this after `setUpProgram()`, in order to make sure that the
368      * correct `mProgram` was set.
369      */
RunProgram(unsigned int event_type)370     void RunProgram(unsigned int event_type) {
371         errno = 0;
372         switch (event_type) {
373             case MEM_EVENT_OOM_KILL:
374                 struct mark_victim_args mark_victim_fake_args;
375                 android::bpf::runProgram(mProgram, &mark_victim_fake_args,
376                                          sizeof(mark_victim_fake_args));
377                 break;
378             case MEM_EVENT_DIRECT_RECLAIM_BEGIN:
379                 struct direct_reclaim_begin_args dr_begin_fake_args;
380                 android::bpf::runProgram(mProgram, &dr_begin_fake_args, sizeof(dr_begin_fake_args));
381                 break;
382             case MEM_EVENT_DIRECT_RECLAIM_END:
383                 struct direct_reclaim_end_args dr_end_fake_args;
384                 android::bpf::runProgram(mProgram, &dr_end_fake_args, sizeof(dr_end_fake_args));
385                 break;
386             case MEM_EVENT_KSWAPD_WAKE:
387                 struct kswapd_wake_args kswapd_wake_fake_args;
388                 android::bpf::runProgram(mProgram, &kswapd_wake_fake_args,
389                                          sizeof(kswapd_wake_fake_args));
390                 break;
391             case MEM_EVENT_KSWAPD_SLEEP:
392                 struct kswapd_sleep_args kswapd_sleep_fake_args;
393                 android::bpf::runProgram(mProgram, &kswapd_sleep_fake_args,
394                                          sizeof(kswapd_sleep_fake_args));
395                 break;
396             default:
397                 FAIL() << "Invalid event type provided";
398         }
399         EXPECT_EQ(errno, 0);
400     }
401 
402   protected:
403     std::unique_ptr<MemEventListener> memevent_listener;
404 
SetUpTestSuite()405     static void SetUpTestSuite() {
406         if (!isAtLeastKernelVersion(5, 8, 0)) {
407             GTEST_SKIP() << "BPF ring buffers not supported below 5.8";
408         }
409     }
410 
SetUp()411     void SetUp() override { initializeTestListener(memevent_listener, false); }
412 
TearDown()413     void TearDown() override { memevent_listener.reset(); }
414 
415     /*
416      * Helper function to insert mocked data into the testing [bpf] ring buffer.
417      * This will trigger the `listen()` if its registered to the given `event_type`.
418      */
setMockDataInRb(mem_event_type_t event_type)419     void setMockDataInRb(mem_event_type_t event_type) {
420         setUpProgram(event_type);
421         RunProgram(event_type);
422     }
423 
424     /*
425      * Test that the `listen()` returns true.
426      * We setup some mocked event data into the testing [bpf] ring-buffer, to make
427      * sure the `listen()` is triggered.
428      */
testListenEvent(unsigned int event_type)429     void testListenEvent(unsigned int event_type) {
430         ASSERT_TRUE(event_type < NR_MEM_EVENTS) << "Invalid event type provided";
431 
432         setMockDataInRb(event_type);
433 
434         ASSERT_TRUE(memevent_listener->listen(5000));  // 5 second timeout
435     }
436 
validateMockedEvent(const mem_event_t & mem_event)437     void validateMockedEvent(const mem_event_t& mem_event) {
438         /*
439          * These values are set inside the testing prog `memevents_test.h`,
440          * they can't be passed from the test to the bpf-prog.
441          */
442         switch (mem_event.type) {
443             case MEM_EVENT_OOM_KILL:
444                 ASSERT_EQ(mem_event.event_data.oom_kill.pid,
445                           mocked_oom_event.event_data.oom_kill.pid)
446                         << "MEM_EVENT_OOM_KILL: Didn't receive expected PID";
447                 ASSERT_EQ(mem_event.event_data.oom_kill.uid,
448                           mocked_oom_event.event_data.oom_kill.uid)
449                         << "MEM_EVENT_OOM_KILL: Didn't receive expected UID";
450                 ASSERT_EQ(mem_event.event_data.oom_kill.oom_score_adj,
451                           mocked_oom_event.event_data.oom_kill.oom_score_adj)
452                         << "MEM_EVENT_OOM_KILL: Didn't receive expected OOM score";
453                 ASSERT_EQ(strcmp(mem_event.event_data.oom_kill.process_name,
454                                  mocked_oom_event.event_data.oom_kill.process_name),
455                           0)
456                         << "MEM_EVENT_OOM_KILL: Didn't receive expected process name";
457                 ASSERT_EQ(mem_event.event_data.oom_kill.timestamp_ms,
458                           mocked_oom_event.event_data.oom_kill.timestamp_ms)
459                         << "MEM_EVENT_OOM_KILL: Didn't receive expected timestamp";
460                 ASSERT_EQ(mem_event.event_data.oom_kill.total_vm_kb,
461                           mocked_oom_event.event_data.oom_kill.total_vm_kb)
462                         << "MEM_EVENT_OOM_KILL: Didn't receive expected total vm";
463                 ASSERT_EQ(mem_event.event_data.oom_kill.anon_rss_kb,
464                           mocked_oom_event.event_data.oom_kill.anon_rss_kb)
465                         << "MEM_EVENT_OOM_KILL: Didn't receive expected anon rss";
466                 ASSERT_EQ(mem_event.event_data.oom_kill.file_rss_kb,
467                           mocked_oom_event.event_data.oom_kill.file_rss_kb)
468                         << "MEM_EVENT_OOM_KILL: Didn't receive expected file rss";
469                 ASSERT_EQ(mem_event.event_data.oom_kill.shmem_rss_kb,
470                           mocked_oom_event.event_data.oom_kill.shmem_rss_kb)
471                         << "MEM_EVENT_OOM_KILL: Didn't receive expected shmem rss";
472                 ASSERT_EQ(mem_event.event_data.oom_kill.pgtables_kb,
473                           mocked_oom_event.event_data.oom_kill.pgtables_kb)
474                         << "MEM_EVENT_OOM_KILL: Didn't receive expected pgtables";
475                 break;
476             case MEM_EVENT_DIRECT_RECLAIM_BEGIN:
477                 /* TP doesn't contain any data to mock */
478                 break;
479             case MEM_EVENT_DIRECT_RECLAIM_END:
480                 /* TP doesn't contain any data to mock */
481                 break;
482             case MEM_EVENT_KSWAPD_WAKE:
483                 ASSERT_EQ(mem_event.event_data.kswapd_wake.node_id,
484                           mocked_kswapd_wake_event.event_data.kswapd_wake.node_id)
485                         << "MEM_EVENT_KSWAPD_WAKE: Didn't receive expected node id";
486                 ASSERT_EQ(mem_event.event_data.kswapd_wake.zone_id,
487                           mocked_kswapd_wake_event.event_data.kswapd_wake.zone_id)
488                         << "MEM_EVENT_KSWAPD_WAKE: Didn't receive expected zone id";
489                 ASSERT_EQ(mem_event.event_data.kswapd_wake.alloc_order,
490                           mocked_kswapd_wake_event.event_data.kswapd_wake.alloc_order)
491                         << "MEM_EVENT_KSWAPD_WAKE: Didn't receive expected alloc_order";
492                 break;
493             case MEM_EVENT_KSWAPD_SLEEP:
494                 ASSERT_EQ(mem_event.event_data.kswapd_sleep.node_id,
495                           mocked_kswapd_sleep_event.event_data.kswapd_sleep.node_id)
496                         << "MEM_EVENT_KSWAPD_SLEEP: Didn't receive expected node id";
497                 break;
498         }
499     }
500 };
501 
502 /*
503  * Validate that `listen()` is triggered when we the bpf-rb receives
504  * a OOM event.
505  */
TEST_F(MemEventsListenerBpf,listener_bpf_oom_kill)506 TEST_F(MemEventsListenerBpf, listener_bpf_oom_kill) {
507     const mem_event_type_t event_type = MEM_EVENT_OOM_KILL;
508 
509     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
510     testListenEvent(event_type);
511 
512     std::vector<mem_event_t> mem_events;
513     ASSERT_TRUE(memevent_listener->getMemEvents(mem_events)) << "Failed fetching events";
514     ASSERT_FALSE(mem_events.empty()) << "Expected for mem_events to have at least 1 mocked event";
515     ASSERT_EQ(mem_events[0].type, event_type) << "Didn't receive a OOM event";
516     validateMockedEvent(mem_events[0]);
517 }
518 
519 /*
520  * Validate that `listen()` is triggered when we the bpf-rb receives
521  * a direct reclain start event.
522  */
TEST_F(MemEventsListenerBpf,listener_bpf_direct_reclaim_begin)523 TEST_F(MemEventsListenerBpf, listener_bpf_direct_reclaim_begin) {
524     const mem_event_type_t event_type = MEM_EVENT_DIRECT_RECLAIM_BEGIN;
525 
526     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
527     testListenEvent(event_type);
528 
529     std::vector<mem_event_t> mem_events;
530     ASSERT_TRUE(memevent_listener->getMemEvents(mem_events)) << "Failed fetching events";
531     ASSERT_FALSE(mem_events.empty()) << "Expected for mem_events to have at least 1 mocked event";
532     ASSERT_EQ(mem_events[0].type, event_type) << "Didn't receive a direct reclaim begin event";
533     validateMockedEvent(mem_events[0]);
534 }
535 
536 /*
537  * Validate that `listen()` is triggered when we the bpf-rb receives
538  * a direct reclain end event.
539  */
TEST_F(MemEventsListenerBpf,listener_bpf_direct_reclaim_end)540 TEST_F(MemEventsListenerBpf, listener_bpf_direct_reclaim_end) {
541     const mem_event_type_t event_type = MEM_EVENT_DIRECT_RECLAIM_END;
542 
543     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
544     testListenEvent(event_type);
545 
546     std::vector<mem_event_t> mem_events;
547     ASSERT_TRUE(memevent_listener->getMemEvents(mem_events)) << "Failed fetching events";
548     ASSERT_FALSE(mem_events.empty()) << "Expected for mem_events to have at least 1 mocked event";
549     ASSERT_EQ(mem_events[0].type, event_type) << "Didn't receive a direct reclaim end event";
550     validateMockedEvent(mem_events[0]);
551 }
552 
TEST_F(MemEventsListenerBpf,listener_bpf_kswapd_wake)553 TEST_F(MemEventsListenerBpf, listener_bpf_kswapd_wake) {
554     const mem_event_type_t event_type = MEM_EVENT_KSWAPD_WAKE;
555 
556     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
557     testListenEvent(event_type);
558 
559     std::vector<mem_event_t> mem_events;
560     ASSERT_TRUE(memevent_listener->getMemEvents(mem_events)) << "Failed fetching events";
561     ASSERT_FALSE(mem_events.empty()) << "Expected for mem_events to have at least 1 mocked event";
562     ASSERT_EQ(mem_events[0].type, event_type) << "Didn't receive a kswapd wake event";
563     validateMockedEvent(mem_events[0]);
564 }
565 
TEST_F(MemEventsListenerBpf,listener_bpf_kswapd_sleep)566 TEST_F(MemEventsListenerBpf, listener_bpf_kswapd_sleep) {
567     const mem_event_type_t event_type = MEM_EVENT_KSWAPD_SLEEP;
568 
569     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
570     testListenEvent(event_type);
571 
572     std::vector<mem_event_t> mem_events;
573     ASSERT_TRUE(memevent_listener->getMemEvents(mem_events)) << "Failed fetching events";
574     ASSERT_FALSE(mem_events.empty()) << "Expected for mem_events to have at least 1 mocked event";
575     ASSERT_EQ(mem_events[0].type, event_type) << "Didn't receive a kswapd sleep event";
576     validateMockedEvent(mem_events[0]);
577 }
578 
579 /*
580  * `listen()` should timeout, and return false, when a memory event that
581  * we are not registered for is triggered.
582  */
TEST_F(MemEventsListenerBpf,no_register_events_listen_fails)583 TEST_F(MemEventsListenerBpf, no_register_events_listen_fails) {
584     const mem_event_type_t event_type = MEM_EVENT_DIRECT_RECLAIM_END;
585     setMockDataInRb(event_type);
586     ASSERT_FALSE(memevent_listener->listen(5000));  // 5 second timeout
587 }
588 
589 /*
590  * `getMemEvents()` should return an empty list, when a memory event that
591  * we are not registered for, is triggered.
592  */
TEST_F(MemEventsListenerBpf,getMemEvents_no_register_events)593 TEST_F(MemEventsListenerBpf, getMemEvents_no_register_events) {
594     const mem_event_type_t event_type = MEM_EVENT_OOM_KILL;
595     setMockDataInRb(event_type);
596 
597     std::vector<mem_event_t> mem_events;
598     ASSERT_TRUE(memevent_listener->getMemEvents(mem_events)) << "Failed fetching events";
599     ASSERT_TRUE(mem_events.empty());
600 }
601 
602 /*
603  * Verify that the listener receives a notification when:
604  * 1. We start listening
605  * 2. Memory event is added in the bpf ring-buffer
606  * 3. Listening is notified of the new event.
607  */
TEST_F(MemEventsListenerBpf,listen_then_create_event)608 TEST_F(MemEventsListenerBpf, listen_then_create_event) {
609     const mem_event_type_t event_type = MEM_EVENT_DIRECT_RECLAIM_BEGIN;
610     std::mutex mtx;
611     std::condition_variable cv;
612     bool didReceiveEvent = false;
613 
614     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
615 
616     std::thread t([&] {
617         bool listen_result = memevent_listener->listen(10000);
618         std::lock_guard lk(mtx);
619         didReceiveEvent = listen_result;
620         cv.notify_one();
621     });
622 
623     setMockDataInRb(event_type);
624 
625     std::unique_lock lk(mtx);
626     cv.wait_for(lk, std::chrono::seconds(10), [&] { return didReceiveEvent; });
627     ASSERT_TRUE(didReceiveEvent) << "Listen never received a memory event notification";
628     t.join();
629 }
630 
631 /*
632  * Similarly to `listen_then_create_event`, but instead of using
633  * `listen()`, we want to poll from `getRingBufferFd()` value.
634  */
TEST_F(MemEventsListenerBpf,getRb_poll_and_create_event)635 TEST_F(MemEventsListenerBpf, getRb_poll_and_create_event) {
636     const mem_event_type_t event_type = MEM_EVENT_DIRECT_RECLAIM_BEGIN;
637     std::mutex mtx;
638     std::condition_variable cv;
639     bool didReceiveEvent = false;
640 
641     ASSERT_TRUE(memevent_listener->registerEvent(event_type));
642 
643     int rb_fd = memevent_listener->getRingBufferFd();
644     ASSERT_GE(rb_fd, 0) << "Received invalid file descriptor";
645 
646     std::thread t([&] {
647         struct pollfd pfd = {
648                 .fd = rb_fd,
649                 .events = POLLIN,
650         };
651         int poll_result = poll(&pfd, 1, 10000);
652         std::lock_guard lk(mtx);
653         didReceiveEvent = poll_result > 0;
654         cv.notify_one();
655     });
656 
657     setMockDataInRb(event_type);
658 
659     std::unique_lock lk(mtx);
660     cv.wait_for(lk, std::chrono::seconds(10), [&] { return didReceiveEvent; });
661     ASSERT_TRUE(didReceiveEvent) << "Poll never received a memory event notification";
662     t.join();
663 }
664 
665 class MemoryPressureTest : public ::testing::Test {
666   public:
SetUpTestSuite()667     static void SetUpTestSuite() {
668         if (!isAtLeastKernelVersion(5, 8, 0))
669             GTEST_SKIP() << "BPF ring buffers not supported below 5.8";
670 
671         if (!std::filesystem::exists(sysrq_trigger_path))
672             GTEST_SKIP() << "sysrq-trigger is required to wake up the OOM killer";
673 
674         ASSERT_TRUE(std::filesystem::exists(MEM_EVENTS_TEST_OOM_MARK_VICTIM_TP))
675                 << "Failed to find test bpf program: " << MEM_EVENTS_TEST_OOM_MARK_VICTIM_TP;
676     }
677 
678   protected:
679     std::unique_ptr<MemEventListener> memevent_listener;
680 
SetUp()681     void SetUp() override { initializeTestListener(memevent_listener, true); }
682 
TearDown()683     void TearDown() override { memevent_listener.reset(); }
684 
685     /**
686      * Helper function that will force the OOM killer to claim a [random]
687      * victim. Note that there is no deterministic way to ensure what process
688      * will be claimed by the OOM killer.
689      *
690      * We utilize [sysrq]
691      * (https://www.kernel.org/doc/html/v4.10/admin-guide/sysrq.html)
692      * to help us attempt to wake up the out-of-memory killer.
693      *
694      * @return true if we were able to trigger an OOM event, false otherwise.
695      */
triggerOom()696     bool triggerOom() {
697         const std::filesystem::path process_oom_path = "proc/self/oom_score_adj";
698 
699         // Make sure that we don't kill the parent process
700         if (!android::base::WriteStringToFile("-999", process_oom_path)) {
701             LOG(ERROR) << "Failed writing oom score adj for parent process";
702             return false;
703         }
704 
705         int pid = fork();
706         if (pid < 0) {
707             LOG(ERROR) << "Failed to fork";
708             return false;
709         }
710         if (pid == 0) {
711             /*
712              * We want to make sure that the OOM killer claims our child
713              * process, this way we ensure we don't kill anything critical
714              * (including this test).
715              */
716             if (!android::base::WriteStringToFile("1000", process_oom_path)) {
717                 LOG(ERROR) << "Failed writing oom score adj for child process";
718                 return false;
719             }
720 
721             struct sysinfo info;
722             if (sysinfo(&info) != 0) {
723                 LOG(ERROR) << "Failed to get sysinfo";
724                 return false;
725             }
726             size_t length = info.freeram / 2;
727 
728             // Allocate memory
729             void* addr =
730                     mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
731             if (addr == MAP_FAILED) {
732                 LOG(ERROR) << "Failed creating mmap";
733                 return false;
734             }
735 
736             // Fault pages
737             srand(67);
738             for (int i = 0; i < length; i += page_size) memset((char*)addr + i, (char)rand(), 1);
739 
740             // Use sysrq-trigger to attempt waking up the OOM killer
741             if (!android::base::WriteStringToFile("f", sysrq_trigger_path)) {
742                 LOG(ERROR) << "Failed calling sysrq to trigger OOM killer";
743                 return false;
744             }
745             sleep(10);  // Give some time in for sysrq to wake up the OOM killer
746         } else {
747             /*
748              * Wait for child process to finish, this will prevent scenario where the `listen()`
749              * is called by the parent, but the child hasn't even been scheduled to run yet.
750              */
751             wait(NULL);
752             if (!memevent_listener->listen(2000)) {
753                 LOG(ERROR) << "Failed to receive a memory event";
754                 return false;
755             }
756         }
757         return true;
758     }
759 
760     /*
761      * This wrapper function exists to facilitate the use of ASSERT, with
762      * non-void helper functions, that want to use `ReadFileToString()`.
763      * We can only assert on void functions.
764      */
fileToString(const std::string & file_path,std::string * content)765     void fileToString(const std::string& file_path, std::string* content) {
766         ASSERT_TRUE(android::base::ReadFileToString(file_path, content))
767                 << "Failed to read file: " << file_path;
768     }
769 
770     /*
771      * Check if the current device supports the new oom/mark_victim tracepoints.
772      * The original oom/mark_victim tracepoint only supports the `pid` field, while
773      * the newer version supports: pid, uid, comm, oom score, pgtables, and rss stats.
774      */
isUpdatedMarkVictimTpSupported()775     bool isUpdatedMarkVictimTpSupported() {
776         const std::string path_mark_victim_format =
777                 "/sys/kernel/tracing/events/oom/mark_victim/format";
778         std::string mark_victim_format_content;
779         fileToString(path_mark_victim_format, &mark_victim_format_content);
780 
781         /*
782          * Check if the device is running the with latest mark_victim fields:
783          * total_vm, anon_rss, file_rss, shmem_rss, uid, pgtables.
784          */
785         return (mark_victim_format_content.find("total_vm") != std::string::npos) &&
786                (mark_victim_format_content.find("anon_rss") != std::string::npos) &&
787                (mark_victim_format_content.find("file_rss") != std::string::npos) &&
788                (mark_victim_format_content.find("shmem_rss") != std::string::npos) &&
789                (mark_victim_format_content.find("uid") != std::string::npos) &&
790                (mark_victim_format_content.find("pgtables") != std::string::npos);
791     }
792 };
793 
794 /**
795  * End-to-end test for listening, and consuming, out-of-memory (OOM) events.
796  *
797  * We don't perform a listen here since the `triggerOom()` already does
798  * that for us.
799  */
TEST_F(MemoryPressureTest,oom_e2e_flow)800 TEST_F(MemoryPressureTest, oom_e2e_flow) {
801     if (!isUpdatedMarkVictimTpSupported())
802         GTEST_SKIP() << "New oom/mark_victim fields not supported";
803 
804     ASSERT_TRUE(memevent_listener->registerEvent(MEM_EVENT_OOM_KILL))
805             << "Failed registering OOM events as an event of interest";
806 
807     ASSERT_TRUE(triggerOom()) << "Failed to trigger OOM killer";
808 
809     std::vector<mem_event_t> oom_events;
810     ASSERT_TRUE(memevent_listener->getMemEvents(oom_events)) << "Failed to fetch memory oom events";
811     ASSERT_FALSE(oom_events.empty()) << "We expect at least 1 OOM event";
812 }
813 
814 /*
815  * Verify that we can register to an event after deregistering from it.
816  */
TEST_F(MemoryPressureTest,register_after_deregister_event)817 TEST_F(MemoryPressureTest, register_after_deregister_event) {
818     if (!isUpdatedMarkVictimTpSupported())
819         GTEST_SKIP() << "New oom/mark_victim fields not supported";
820 
821     ASSERT_TRUE(memevent_listener->registerEvent(MEM_EVENT_OOM_KILL))
822             << "Failed registering OOM events as an event of interest";
823 
824     ASSERT_TRUE(memevent_listener->deregisterEvent(MEM_EVENT_OOM_KILL))
825             << "Failed deregistering OOM events";
826 
827     ASSERT_TRUE(memevent_listener->registerEvent(MEM_EVENT_OOM_KILL))
828             << "Failed to register for OOM events after deregister it";
829 }
830 
main(int argc,char ** argv)831 int main(int argc, char** argv) {
832     ::testing::InitGoogleTest(&argc, argv);
833     ::android::base::InitLogging(argv, android::base::StderrLogger);
834     return RUN_ALL_TESTS();
835 }
836