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