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/memory/post_delayed_memory_reduction_task.h"
6
7 #include "base/timer/timer.h"
8
9 #if BUILDFLAG(IS_ANDROID)
10 #include "base/android/pre_freeze_background_memory_trimmer.h"
11 #endif
12
13 namespace base {
14
PostDelayedMemoryReductionTask(scoped_refptr<SequencedTaskRunner> task_runner,const Location & from_here,OnceClosure task,base::TimeDelta delay)15 void PostDelayedMemoryReductionTask(
16 scoped_refptr<SequencedTaskRunner> task_runner,
17 const Location& from_here,
18 OnceClosure task,
19 base::TimeDelta delay) {
20 #if BUILDFLAG(IS_ANDROID)
21 android::PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
22 std::move(task_runner), from_here, std::move(task), delay);
23 #else
24 task_runner->PostDelayedTask(from_here, std::move(task), delay);
25 #endif
26 }
27
PostDelayedMemoryReductionTask(scoped_refptr<SequencedTaskRunner> task_runner,const Location & from_here,OnceCallback<void (MemoryReductionTaskContext)> task,base::TimeDelta delay)28 void PostDelayedMemoryReductionTask(
29 scoped_refptr<SequencedTaskRunner> task_runner,
30 const Location& from_here,
31 OnceCallback<void(MemoryReductionTaskContext)> task,
32 base::TimeDelta delay) {
33 #if BUILDFLAG(IS_ANDROID)
34 android::PreFreezeBackgroundMemoryTrimmer::PostDelayedBackgroundTask(
35 std::move(task_runner), from_here, std::move(task), delay);
36 #else
37 task_runner->PostDelayedTask(
38 from_here,
39 BindOnce(std::move(task), MemoryReductionTaskContext::kDelayExpired),
40 delay);
41 #endif // BUILDFLAG(IS_ANDROID)
42 }
43
44 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
45 * *
46 * OneShotDelayedBackgroundTimer::TimerImpl *
47 * *
48 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
49
50 // This implementation is just a small wrapper around a |base::OneShotTimer|.
51 class OneShotDelayedBackgroundTimer::TimerImpl final
52 : public OneShotDelayedBackgroundTimer::OneShotDelayedBackgroundTimerImpl {
53 public:
54 ~TimerImpl() override = default;
Start(const Location & from_here,TimeDelta delay,OnceCallback<void (MemoryReductionTaskContext)> task)55 void Start(const Location& from_here,
56 TimeDelta delay,
57 OnceCallback<void(MemoryReductionTaskContext)> task) override {
58 timer_.Start(
59 from_here, delay,
60 BindOnce(std::move(task), MemoryReductionTaskContext::kDelayExpired));
61 }
Stop()62 void Stop() override { timer_.Stop(); }
IsRunning() const63 bool IsRunning() const override { return timer_.IsRunning(); }
SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner)64 void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) override {
65 timer_.SetTaskRunner(std::move(task_runner));
66 }
67
68 private:
69 OneShotTimer timer_;
70 };
71
72 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
73 * *
74 * TaskImpl *
75 * *
76 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
77
78 #if BUILDFLAG(IS_ANDROID)
79 class OneShotDelayedBackgroundTimer::TaskImpl final
80 : public OneShotDelayedBackgroundTimer::OneShotDelayedBackgroundTimerImpl {
81 public:
82 ~TaskImpl() override = default;
Start(const Location & from_here,TimeDelta delay,OnceCallback<void (MemoryReductionTaskContext)> task)83 void Start(const Location& from_here,
84 TimeDelta delay,
85 OnceCallback<void(MemoryReductionTaskContext)> task) override {
86 this->StartInternal(
87 from_here, delay,
88 BindOnce(
89 [](TaskImpl* timer,
90 OnceCallback<void(MemoryReductionTaskContext)> task,
91 MemoryReductionTaskContext in_pre_freeze) {
92 std::move(task).Run(in_pre_freeze);
93 timer->task_ = nullptr;
94 },
95 // |base::Unretained(this)| is safe here because destroying this
96 // will cancel the task. We do not need to worry about race
97 // conditions here because destruction should always happen on the
98 // same thread that the task is started on.
99 base::Unretained(this), std::move(task)));
100 }
StartInternal(const Location & from_here,TimeDelta delay,OnceCallback<void (MemoryReductionTaskContext)> task)101 void StartInternal(const Location& from_here,
102 TimeDelta delay,
103 OnceCallback<void(MemoryReductionTaskContext)> task) {
104 if (IsRunning()) {
105 Stop();
106 }
107 DCHECK(GetTaskRunner()->RunsTasksInCurrentSequence());
108 base::AutoLock locker(
109 android::PreFreezeBackgroundMemoryTrimmer::Instance().lock_);
110 task_ = android::PreFreezeBackgroundMemoryTrimmer::Instance()
111 .PostDelayedBackgroundTaskModernHelper(
112 GetTaskRunner(), from_here, std::move(task), delay);
113 }
Stop()114 void Stop() override {
115 if (IsRunning()) {
116 task_.ExtractAsDangling()->CancelTask();
117 }
118 }
IsRunning() const119 bool IsRunning() const override { return task_ != nullptr; }
SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner)120 void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) override {
121 task_runner_ = task_runner;
122 }
123
124 private:
GetTaskRunner()125 scoped_refptr<SequencedTaskRunner> GetTaskRunner() {
126 // This matches the semantics of |OneShotTimer::GetTaskRunner()|.
127 return task_runner_ ? task_runner_
128 : SequencedTaskRunner::GetCurrentDefault();
129 }
130
131 raw_ptr<android::PreFreezeBackgroundMemoryTrimmer::BackgroundTask> task_ =
132 nullptr;
133 scoped_refptr<SequencedTaskRunner> task_runner_ = nullptr;
134 };
135 #endif
136
137 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
138 * *
139 * OneShotDelayedBackgroundTimer *
140 * *
141 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
142
OneShotDelayedBackgroundTimer()143 OneShotDelayedBackgroundTimer::OneShotDelayedBackgroundTimer() {
144 #if BUILDFLAG(IS_ANDROID)
145 if (android::PreFreezeBackgroundMemoryTrimmer::ShouldUseModernTrim()) {
146 impl_ = std::make_unique<TaskImpl>();
147 } else {
148 impl_ = std::make_unique<TimerImpl>();
149 }
150 #else
151 impl_ = std::make_unique<TimerImpl>();
152 #endif
153 }
154
~OneShotDelayedBackgroundTimer()155 OneShotDelayedBackgroundTimer::~OneShotDelayedBackgroundTimer() {
156 Stop();
157 }
158
Stop()159 void OneShotDelayedBackgroundTimer::Stop() {
160 impl_->Stop();
161 }
162
IsRunning() const163 bool OneShotDelayedBackgroundTimer::IsRunning() const {
164 return impl_->IsRunning();
165 }
166
SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner)167 void OneShotDelayedBackgroundTimer::SetTaskRunner(
168 scoped_refptr<SequencedTaskRunner> task_runner) {
169 impl_->SetTaskRunner(std::move(task_runner));
170 }
171
Start(const Location & from_here,TimeDelta delay,OnceCallback<void (MemoryReductionTaskContext)> task)172 void OneShotDelayedBackgroundTimer::Start(
173 const Location& from_here,
174 TimeDelta delay,
175 OnceCallback<void(MemoryReductionTaskContext)> task) {
176 #if BUILDFLAG(IS_ANDROID)
177 android::PreFreezeBackgroundMemoryTrimmer::SetDidRegisterTask();
178 #endif
179 impl_->Start(from_here, delay, std::move(task));
180 }
181
182 } // namespace base
183