1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/android/pre_freeze_background_memory_trimmer.h"
6
7 #include <optional>
8
9 #include "base/task/thread_pool.h"
10 #include "base/test/scoped_feature_list.h"
11 #include "base/test/task_environment.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace base::android {
15
16 namespace {
17
18 static int s_counter = 0;
19
ResetGlobalCounter()20 void ResetGlobalCounter() {
21 s_counter = 0;
22 }
23
IncGlobalCounter()24 void IncGlobalCounter() {
25 s_counter++;
26 }
27
DecGlobalCounter()28 void DecGlobalCounter() {
29 s_counter--;
30 }
31
PostDelayedIncGlobal()32 void PostDelayedIncGlobal() {
33 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
34 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
35 base::BindRepeating(&IncGlobalCounter), base::Seconds(10));
36 }
37
38 } // namespace
39
40 class PreFreezeBackgroundMemoryTrimmerTest : public testing::Test {
41 public:
PreFreezeBackgroundMemoryTrimmerTest()42 PreFreezeBackgroundMemoryTrimmerTest() {
43 fl_.InitAndEnableFeature(kOnPreFreezeMemoryTrim);
44 }
SetUp()45 void SetUp() override {
46 PreFreezeBackgroundMemoryTrimmer::SetSupportsModernTrimForTesting(true);
47 PreFreezeBackgroundMemoryTrimmer::SetDidRegisterTasksForTesting(false);
48 ResetGlobalCounter();
49 }
50
51 protected:
pending_task_count()52 size_t pending_task_count() {
53 return PreFreezeBackgroundMemoryTrimmer::Instance()
54 .GetNumberOfPendingBackgroundTasksForTesting();
55 }
56
did_register_tasks()57 bool did_register_tasks() {
58 return PreFreezeBackgroundMemoryTrimmer::Instance()
59 .DidRegisterTasksForTesting();
60 }
61
62 test::TaskEnvironment task_environment_{
63 base::test::TaskEnvironment::TimeSource::MOCK_TIME};
64 private:
65 test::ScopedFeatureList fl_;
66 };
67
68 // We do not expect any tasks to be registered with
69 // PreFreezeBackgroundMemoryTrimmer on Android versions before U.
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,PostTaskPreFreezeUnsupported)70 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, PostTaskPreFreezeUnsupported) {
71 PreFreezeBackgroundMemoryTrimmer::SetSupportsModernTrimForTesting(false);
72
73 ASSERT_FALSE(did_register_tasks());
74
75 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
76 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
77 base::BindRepeating(&IncGlobalCounter), base::Seconds(30));
78
79 ASSERT_EQ(pending_task_count(), 0u);
80 ASSERT_FALSE(did_register_tasks());
81
82 task_environment_.FastForwardBy(base::Seconds(30));
83
84 ASSERT_EQ(pending_task_count(), 0u);
85 EXPECT_EQ(s_counter, 1);
86 }
87
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,PostTaskPreFreezeWithoutTrim)88 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, PostTaskPreFreezeWithoutTrim) {
89 test::ScopedFeatureList fl;
90 fl.InitAndDisableFeature(kOnPreFreezeMemoryTrim);
91 ASSERT_FALSE(did_register_tasks());
92
93 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
94 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
95 base::BindRepeating(&IncGlobalCounter), base::Seconds(30));
96
97 ASSERT_EQ(pending_task_count(), 0u);
98 ASSERT_TRUE(did_register_tasks());
99
100 task_environment_.FastForwardBy(base::Seconds(30));
101
102 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
103
104 ASSERT_EQ(pending_task_count(), 0u);
105 EXPECT_EQ(s_counter, 1);
106 }
107
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,PostDelayedTaskSimple)108 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, PostDelayedTaskSimple) {
109 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
110 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
111 base::BindRepeating(&IncGlobalCounter), base::Seconds(30));
112
113 ASSERT_TRUE(did_register_tasks());
114 ASSERT_EQ(pending_task_count(), 1u);
115
116 task_environment_.FastForwardBy(base::Seconds(30));
117
118 ASSERT_EQ(pending_task_count(), 0u);
119
120 EXPECT_EQ(s_counter, 1);
121 }
122
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,PostDelayedTaskMultiple)123 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, PostDelayedTaskMultiple) {
124 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
125 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
126 base::BindRepeating(&IncGlobalCounter), base::Seconds(40));
127
128 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
129 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
130 base::BindRepeating(&IncGlobalCounter), base::Seconds(30));
131
132 ASSERT_EQ(pending_task_count(), 2u);
133
134 task_environment_.FastForwardBy(base::Seconds(30));
135
136 ASSERT_EQ(pending_task_count(), 1u);
137
138 EXPECT_EQ(s_counter, 1);
139
140 task_environment_.FastForwardBy(base::Seconds(10));
141
142 ASSERT_EQ(pending_task_count(), 0u);
143
144 EXPECT_EQ(s_counter, 2);
145 }
146
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,PostDelayedTaskPreFreeze)147 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, PostDelayedTaskPreFreeze) {
148 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
149 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
150 base::BindRepeating(&IncGlobalCounter), base::Seconds(60));
151
152 ASSERT_EQ(pending_task_count(), 1u);
153
154 task_environment_.FastForwardBy(base::Seconds(30));
155
156 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
157
158 ASSERT_EQ(pending_task_count(), 0u);
159
160 EXPECT_EQ(s_counter, 1);
161 }
162
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,PostDelayedTaskMultiThreaded)163 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, PostDelayedTaskMultiThreaded) {
164 base::WaitableEvent event1(base::WaitableEvent::ResetPolicy::MANUAL,
165 base::WaitableEvent::InitialState::NOT_SIGNALED);
166 base::WaitableEvent event2(base::WaitableEvent::ResetPolicy::MANUAL,
167 base::WaitableEvent::InitialState::NOT_SIGNALED);
168 auto task_runner =
169 base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
170 ASSERT_FALSE(task_runner->RunsTasksInCurrentSequence());
171
172 task_runner->PostTask(
173 FROM_HERE,
174 base::BindOnce(
175 [](scoped_refptr<base::SequencedTaskRunner> task_runner,
176 base::WaitableEvent* event1, base::WaitableEvent* event2) {
177 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
178 task_runner, FROM_HERE,
179 base::BindOnce(
180 [](base::WaitableEvent* event) {
181 IncGlobalCounter();
182 event->Signal();
183 },
184 base::Unretained(event2)),
185 base::Seconds(30));
186 event1->Signal();
187 },
188 task_runner, base::Unretained(&event1), base::Unretained(&event2)));
189
190 task_environment_.FastForwardBy(base::Seconds(1));
191
192 event1.Wait();
193
194 ASSERT_EQ(pending_task_count(), 1u);
195
196 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
197
198 event2.Wait();
199
200 ASSERT_EQ(pending_task_count(), 0u);
201
202 EXPECT_EQ(s_counter, 1);
203 }
204
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,PostDelayedTaskBeforeAndAfterPreFreeze)205 TEST_F(PreFreezeBackgroundMemoryTrimmerTest,
206 PostDelayedTaskBeforeAndAfterPreFreeze) {
207 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
208 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
209 base::BindRepeating(&IncGlobalCounter), base::Seconds(60));
210
211 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
212 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
213 base::BindRepeating(&IncGlobalCounter), base::Seconds(30));
214
215 ASSERT_EQ(pending_task_count(), 2u);
216
217 task_environment_.FastForwardBy(base::Seconds(30));
218
219 ASSERT_EQ(pending_task_count(), 1u);
220
221 EXPECT_EQ(s_counter, 1);
222
223 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
224
225 ASSERT_EQ(pending_task_count(), 0u);
226
227 EXPECT_EQ(s_counter, 2);
228 }
229
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,AddDuringPreFreeze)230 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, AddDuringPreFreeze) {
231 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
232 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
233 base::BindRepeating(&PostDelayedIncGlobal), base::Seconds(10));
234
235 ASSERT_EQ(pending_task_count(), 1u);
236
237 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
238
239 ASSERT_EQ(pending_task_count(), 1u);
240 EXPECT_EQ(s_counter, 0);
241
242 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
243
244 ASSERT_EQ(pending_task_count(), 0u);
245
246 EXPECT_EQ(s_counter, 1);
247 }
248
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,AddDuringPreFreezeRunNormally)249 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, AddDuringPreFreezeRunNormally) {
250 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
251 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
252 base::BindRepeating(&PostDelayedIncGlobal), base::Seconds(10));
253
254 ASSERT_EQ(pending_task_count(), 1u);
255
256 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
257
258 ASSERT_EQ(pending_task_count(), 1u);
259 EXPECT_EQ(s_counter, 0);
260
261 task_environment_.FastForwardBy(base::Seconds(30));
262
263 ASSERT_EQ(pending_task_count(), 0u);
264
265 EXPECT_EQ(s_counter, 1);
266 }
267
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,TimerNeverStarted)268 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, TimerNeverStarted) {
269 OneShotDelayedBackgroundTimer timer;
270
271 ASSERT_EQ(pending_task_count(), 0u);
272 ASSERT_FALSE(timer.IsRunning());
273
274 task_environment_.FastForwardBy(base::Seconds(30));
275
276 ASSERT_EQ(pending_task_count(), 0u);
277 ASSERT_FALSE(timer.IsRunning());
278
279 ASSERT_FALSE(did_register_tasks());
280 EXPECT_EQ(s_counter, 0);
281 }
282
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,TimerFastForward)283 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, TimerFastForward) {
284 OneShotDelayedBackgroundTimer timer;
285
286 ASSERT_EQ(pending_task_count(), 0u);
287 ASSERT_FALSE(timer.IsRunning());
288 ASSERT_FALSE(did_register_tasks());
289
290 timer.Start(FROM_HERE, base::Seconds(30), base::BindOnce(&IncGlobalCounter));
291
292 ASSERT_EQ(pending_task_count(), 1u);
293 ASSERT_TRUE(timer.IsRunning());
294 ASSERT_TRUE(did_register_tasks());
295
296 task_environment_.FastForwardBy(base::Seconds(30));
297
298 ASSERT_EQ(pending_task_count(), 0u);
299 ASSERT_FALSE(timer.IsRunning());
300
301 EXPECT_EQ(s_counter, 1);
302 }
303
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,TimerOnPreFreeze)304 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, TimerOnPreFreeze) {
305 OneShotDelayedBackgroundTimer timer;
306
307 ASSERT_EQ(pending_task_count(), 0u);
308 ASSERT_FALSE(timer.IsRunning());
309 ASSERT_FALSE(did_register_tasks());
310
311 timer.Start(FROM_HERE, base::Seconds(30), base::BindOnce(&IncGlobalCounter));
312
313 ASSERT_EQ(pending_task_count(), 1u);
314 ASSERT_TRUE(timer.IsRunning());
315 ASSERT_TRUE(did_register_tasks());
316
317 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
318
319 ASSERT_EQ(pending_task_count(), 0u);
320 ASSERT_FALSE(timer.IsRunning());
321
322 EXPECT_EQ(s_counter, 1);
323 }
324
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,TimerStopSingle)325 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, TimerStopSingle) {
326 OneShotDelayedBackgroundTimer timer;
327
328 ASSERT_EQ(pending_task_count(), 0u);
329 ASSERT_FALSE(timer.IsRunning());
330 ASSERT_FALSE(did_register_tasks());
331
332 timer.Start(FROM_HERE, base::Seconds(30), base::BindOnce(&IncGlobalCounter));
333
334 ASSERT_EQ(pending_task_count(), 1u);
335 ASSERT_TRUE(timer.IsRunning());
336 ASSERT_TRUE(did_register_tasks());
337
338 timer.Stop();
339 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
340
341 ASSERT_EQ(pending_task_count(), 0u);
342 ASSERT_FALSE(timer.IsRunning());
343
344 EXPECT_EQ(s_counter, 0);
345 }
346
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,TimerStopMultiple)347 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, TimerStopMultiple) {
348 OneShotDelayedBackgroundTimer timer;
349
350 ASSERT_EQ(pending_task_count(), 0u);
351 ASSERT_FALSE(timer.IsRunning());
352 ASSERT_FALSE(did_register_tasks());
353
354 timer.Start(FROM_HERE, base::Seconds(30), base::BindOnce(&IncGlobalCounter));
355
356 ASSERT_EQ(pending_task_count(), 1u);
357 ASSERT_TRUE(timer.IsRunning());
358 ASSERT_TRUE(did_register_tasks());
359
360 timer.Stop();
361 timer.Stop();
362
363 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
364
365 ASSERT_EQ(pending_task_count(), 0u);
366 ASSERT_FALSE(timer.IsRunning());
367
368 EXPECT_EQ(s_counter, 0);
369 }
370
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,TimerDestroyed)371 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, TimerDestroyed) {
372 // Add scope here to destroy timer.
373 {
374 OneShotDelayedBackgroundTimer timer;
375
376 ASSERT_EQ(pending_task_count(), 0u);
377 ASSERT_FALSE(timer.IsRunning());
378 ASSERT_FALSE(did_register_tasks());
379
380 timer.Start(FROM_HERE, base::Seconds(30),
381 base::BindOnce(&IncGlobalCounter));
382
383 ASSERT_EQ(pending_task_count(), 1u);
384 ASSERT_TRUE(timer.IsRunning());
385 ASSERT_TRUE(did_register_tasks());
386 }
387
388 ASSERT_EQ(pending_task_count(), 0u);
389
390 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
391
392 ASSERT_EQ(pending_task_count(), 0u);
393
394 EXPECT_EQ(s_counter, 0);
395 }
396
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,TimerStartedWhileRunning)397 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, TimerStartedWhileRunning) {
398 IncGlobalCounter();
399 ASSERT_EQ(s_counter, 1);
400
401 OneShotDelayedBackgroundTimer timer;
402
403 ASSERT_EQ(pending_task_count(), 0u);
404 ASSERT_FALSE(timer.IsRunning());
405 ASSERT_FALSE(did_register_tasks());
406
407 timer.Start(FROM_HERE, base::Seconds(30), base::BindOnce(&IncGlobalCounter));
408
409 ASSERT_EQ(pending_task_count(), 1u);
410 ASSERT_TRUE(timer.IsRunning());
411 ASSERT_TRUE(did_register_tasks());
412
413 timer.Start(FROM_HERE, base::Seconds(10), base::BindOnce(&DecGlobalCounter));
414
415 // Previous task was cancelled, so s_counter should still be 1.
416 ASSERT_EQ(s_counter, 1);
417 ASSERT_EQ(pending_task_count(), 1u);
418 ASSERT_TRUE(timer.IsRunning());
419 ASSERT_TRUE(did_register_tasks());
420
421 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
422
423 ASSERT_EQ(pending_task_count(), 0u);
424 ASSERT_FALSE(timer.IsRunning());
425 ASSERT_TRUE(did_register_tasks());
426
427 // Expect 0 here because we decremented it. The incrementing task was
428 // cancelled when we restarted the experiment.
429 EXPECT_EQ(s_counter, 0);
430 }
431
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,BoolTaskRunDirectly)432 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, BoolTaskRunDirectly) {
433 std::optional<MemoryReductionTaskContext> called_task_type = std::nullopt;
434 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
435 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
436 base::BindOnce(
437 [](std::optional<MemoryReductionTaskContext>& called_task_type,
438 MemoryReductionTaskContext task_type) {
439 called_task_type = task_type;
440 },
441 std::ref(called_task_type)),
442 base::Seconds(30));
443
444 ASSERT_FALSE(called_task_type.has_value());
445 ASSERT_EQ(pending_task_count(), 1u);
446
447 task_environment_.FastForwardBy(base::Seconds(30));
448
449 ASSERT_EQ(pending_task_count(), 0u);
450 EXPECT_EQ(called_task_type.value(),
451 MemoryReductionTaskContext::kDelayExpired);
452 }
453
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,BoolTaskRunFromPreFreeze)454 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, BoolTaskRunFromPreFreeze) {
455 std::optional<MemoryReductionTaskContext> called_task_type = std::nullopt;
456 PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
457 SingleThreadTaskRunner::GetCurrentDefault(), FROM_HERE,
458 base::BindOnce(
459 [](std::optional<MemoryReductionTaskContext>& called_task_type,
460 MemoryReductionTaskContext task_type) {
461 called_task_type = task_type;
462 },
463 std::ref(called_task_type)),
464 base::Seconds(30));
465
466 ASSERT_FALSE(called_task_type.has_value());
467 ASSERT_EQ(pending_task_count(), 1u);
468
469 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
470
471 ASSERT_EQ(pending_task_count(), 0u);
472 EXPECT_EQ(called_task_type.value(), MemoryReductionTaskContext::kProactive);
473 }
474
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,TimerBoolTaskRunDirectly)475 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, TimerBoolTaskRunDirectly) {
476 OneShotDelayedBackgroundTimer timer;
477 std::optional<MemoryReductionTaskContext> called_task_type = std::nullopt;
478
479 ASSERT_EQ(pending_task_count(), 0u);
480 ASSERT_FALSE(timer.IsRunning());
481
482 timer.Start(
483 FROM_HERE, base::Seconds(30),
484 base::BindOnce(
485 [](std::optional<MemoryReductionTaskContext>& called_task_type,
486 MemoryReductionTaskContext task_type) {
487 called_task_type = task_type;
488 },
489 std::ref(called_task_type)));
490
491 ASSERT_FALSE(called_task_type.has_value());
492 ASSERT_EQ(pending_task_count(), 1u);
493
494 task_environment_.FastForwardBy(base::Seconds(30));
495
496 ASSERT_EQ(pending_task_count(), 0u);
497 EXPECT_EQ(called_task_type.value(),
498 MemoryReductionTaskContext::kDelayExpired);
499 }
500
TEST_F(PreFreezeBackgroundMemoryTrimmerTest,TimerBoolTaskRunFromPreFreeze)501 TEST_F(PreFreezeBackgroundMemoryTrimmerTest, TimerBoolTaskRunFromPreFreeze) {
502 OneShotDelayedBackgroundTimer timer;
503 std::optional<MemoryReductionTaskContext> called_task_type = std::nullopt;
504
505 ASSERT_EQ(pending_task_count(), 0u);
506 ASSERT_FALSE(timer.IsRunning());
507
508 timer.Start(
509 FROM_HERE, base::Seconds(30),
510 base::BindOnce(
511 [](std::optional<MemoryReductionTaskContext>& called_task_type,
512 MemoryReductionTaskContext task_type) {
513 called_task_type = task_type;
514 },
515 std::ref(called_task_type)));
516
517 ASSERT_FALSE(called_task_type.has_value());
518 ASSERT_EQ(pending_task_count(), 1u);
519
520 PreFreezeBackgroundMemoryTrimmer::OnPreFreezeForTesting();
521
522 ASSERT_EQ(pending_task_count(), 0u);
523 EXPECT_EQ(called_task_type.value(), MemoryReductionTaskContext::kProactive);
524 }
525
526 } // namespace base::android
527