xref: /aosp_15_r20/external/cronet/base/android/pre_freeze_background_memory_trimmer.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 #ifndef BASE_ANDROID_PRE_FREEZE_BACKGROUND_MEMORY_TRIMMER_H_
6 #define BASE_ANDROID_PRE_FREEZE_BACKGROUND_MEMORY_TRIMMER_H_
7 
8 #include <deque>
9 
10 #include "base/cancelable_callback.h"
11 #include "base/feature_list.h"
12 #include "base/memory/post_delayed_memory_reduction_task.h"
13 #include "base/no_destructor.h"
14 #include "base/task/delayed_task_handle.h"
15 #include "base/task/sequenced_task_runner.h"
16 #include "base/timer/timer.h"
17 
18 namespace base::android {
19 class MemoryPurgeManagerAndroid;
20 
21 BASE_EXPORT BASE_DECLARE_FEATURE(kOnPreFreezeMemoryTrim);
22 
23 // Starting from Android U, apps are frozen shortly after being backgrounded
24 // (with some exceptions). This causes some background tasks for reclaiming
25 // resources in Chrome to not be run until Chrome is foregrounded again (which
26 // completely defeats their purpose).
27 //
28 // To try to avoid this problem, we use the |PostDelayedBackgroundTask| found
29 // below. Prior to Android U, this will simply post the task in the background
30 // with the given delay. From Android U onwards, this will post the task in the
31 // background with the given delay, but will run it sooner if we are about to
32 // be frozen.
33 class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer {
34  public:
35   static PreFreezeBackgroundMemoryTrimmer& Instance();
36   ~PreFreezeBackgroundMemoryTrimmer() = delete;
37 
38   // Posts a delayed task. On versions of Android starting from U, may run the
39   // task sooner if we are backgrounded. In this case, we run the task on the
40   // correct task runner, ignoring the given delay.
PostDelayedBackgroundTask(scoped_refptr<base::SequencedTaskRunner> task_runner,const base::Location & from_here,OnceCallback<void (void)> task,base::TimeDelta delay)41   static void PostDelayedBackgroundTask(
42       scoped_refptr<base::SequencedTaskRunner> task_runner,
43       const base::Location& from_here,
44       OnceCallback<void(void)> task,
45       base::TimeDelta delay) LOCKS_EXCLUDED(lock_) {
46     PostDelayedBackgroundTask(
47         task_runner, from_here,
48         BindOnce(
49             [](OnceClosure task,
50                MemoryReductionTaskContext called_from_prefreeze) {
51               std::move(task).Run();
52             },
53             std::move(task)),
54         delay);
55   }
56   static void PostDelayedBackgroundTask(
57       scoped_refptr<base::SequencedTaskRunner> task_runner,
58       const base::Location& from_here,
59       OnceCallback<void(MemoryReductionTaskContext)> task,
60       base::TimeDelta delay) LOCKS_EXCLUDED(lock_);
61 
62   static void SetSupportsModernTrimForTesting(bool is_supported);
63   static void SetDidRegisterTasksForTesting(bool did_register_tasks);
64   size_t GetNumberOfPendingBackgroundTasksForTesting() LOCKS_EXCLUDED(lock_);
65   bool DidRegisterTasksForTesting();
66 
OnPreFreezeForTesting()67   static void OnPreFreezeForTesting() LOCKS_EXCLUDED(lock_) { OnPreFreeze(); }
68 
69   // Called when Chrome is about to be frozen. Runs as many delayed tasks as
70   // possible immediately, before we are frozen.
71   static void OnPreFreeze() LOCKS_EXCLUDED(lock_);
72 
73   static bool SupportsModernTrim();
74   static bool ShouldUseModernTrim();
75 
76  private:
77   friend class base::NoDestructor<PreFreezeBackgroundMemoryTrimmer>;
78   friend jboolean JNI_MemoryPurgeManager_IsOnPreFreezeMemoryTrimEnabled(
79       JNIEnv* env);
80   friend class base::android::MemoryPurgeManagerAndroid;
81   friend class base::OneShotDelayedBackgroundTimer;
82 
83   // We use our own implementation here, based on |PostCancelableDelayedTask|,
84   // rather than relying on something like |base::OneShotTimer|, since
85   // |base::OneShotTimer| doesn't support things like immediately running our
86   // task from a different sequence, and some |base::OneShotTimer|
87   // functionality (e.g. |FireNow|) only works with the default task runner.
88   class BackgroundTask final {
89    public:
90     static std::unique_ptr<BackgroundTask> Create(
91         scoped_refptr<base::SequencedTaskRunner> task_runner,
92         const base::Location& from_here,
93         OnceCallback<void(MemoryReductionTaskContext)> task,
94         base::TimeDelta delay);
95 
96     explicit BackgroundTask(
97         scoped_refptr<base::SequencedTaskRunner> task_runner);
98     ~BackgroundTask();
99 
100     static void RunNow(std::unique_ptr<BackgroundTask> background_task);
101 
102     void Run(MemoryReductionTaskContext from_pre_freeze);
103 
104     void CancelTask();
105 
106    private:
107     friend class PreFreezeBackgroundMemoryTrimmer;
108     void Start(const Location& from_here,
109                TimeDelta delay,
110                OnceCallback<void(MemoryReductionTaskContext)> task);
111     void StartInternal(const Location& from_here,
112                        TimeDelta delay,
113                        OnceClosure task);
114     scoped_refptr<base::SequencedTaskRunner> task_runner_;
115     base::DelayedTaskHandle task_handle_;
116 
117     OnceCallback<void(MemoryReductionTaskContext)> task_;
118   };
119 
120   PreFreezeBackgroundMemoryTrimmer();
121 
122   static void UnregisterBackgroundTask(BackgroundTask*) LOCKS_EXCLUDED(lock_);
123 
124   void UnregisterBackgroundTaskInternal(BackgroundTask*) LOCKS_EXCLUDED(lock_);
125 
126   static void SetDidRegisterTask() LOCKS_EXCLUDED(lock_);
127   void SetDidRegisterTaskInternal() LOCKS_EXCLUDED(lock_);
128 
129   void PostDelayedBackgroundTaskInternal(
130       scoped_refptr<base::SequencedTaskRunner> task_runner,
131       const base::Location& from_here,
132       OnceCallback<void(MemoryReductionTaskContext)> task,
133       base::TimeDelta delay) LOCKS_EXCLUDED(lock_);
134   void PostDelayedBackgroundTaskModern(
135       scoped_refptr<base::SequencedTaskRunner> task_runner,
136       const base::Location& from_here,
137       OnceCallback<void(MemoryReductionTaskContext)> task,
138       base::TimeDelta delay) LOCKS_EXCLUDED(lock_);
139   BackgroundTask* PostDelayedBackgroundTaskModernHelper(
140       scoped_refptr<base::SequencedTaskRunner> task_runner,
141       const base::Location& from_here,
142       OnceCallback<void(MemoryReductionTaskContext)> task,
143       base::TimeDelta delay) EXCLUSIVE_LOCKS_REQUIRED(lock_);
144 
145   void OnPreFreezeInternal() LOCKS_EXCLUDED(lock_);
146 
147   void PostMetricsTask(std::optional<uint64_t> pmf_before);
148 
149   mutable base::Lock lock_;
150   std::deque<std::unique_ptr<BackgroundTask>> background_tasks_
151       GUARDED_BY(lock_);
152   // Keeps track of whether any tasks have been registered so far (set to true
153   // once the first task is registered).
154   bool did_register_task_ GUARDED_BY(lock_) = false;
155   bool supports_modern_trim_;
156 };
157 
158 }  // namespace base::android
159 
160 #endif  // BASE_ANDROID_PRE_FREEZE_BACKGROUND_MEMORY_TRIMMER_H_
161