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