Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: chrome/browser/memory/tab_manager.h

Issue 2898033002: [TabManager] Move TabManager into chrome/browser/resource_coordinator. (Closed)
Patch Set: rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 CHROME_BROWSER_MEMORY_TAB_MANAGER_H_
6 #define CHROME_BROWSER_MEMORY_TAB_MANAGER_H_
7
8 #include <stdint.h>
9
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14
15 #include "base/callback.h"
16 #include "base/compiler_specific.h"
17 #include "base/gtest_prod_util.h"
18 #include "base/macros.h"
19 #include "base/memory/memory_pressure_listener.h"
20 #include "base/memory/weak_ptr.h"
21 #include "base/observer_list.h"
22 #include "base/strings/string16.h"
23 #include "base/timer/timer.h"
24 #include "build/build_config.h"
25 #include "chrome/browser/memory/tab_manager_observer.h"
26 #include "chrome/browser/memory/tab_stats.h"
27 #include "chrome/browser/ui/browser_tab_strip_tracker.h"
28 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
29
30 class BrowserList;
31 class GURL;
32 class TabStripModel;
33
34 namespace base {
35 class TickClock;
36 }
37
38 namespace content {
39 class WebContents;
40 }
41
42 namespace memory {
43
44 #if defined(OS_CHROMEOS)
45 class TabManagerDelegate;
46 #endif
47
48 // The TabManager periodically updates (see
49 // |kAdjustmentIntervalSeconds| in the source) the status of renderers
50 // which are then used by the algorithm embedded here for priority in being
51 // killed upon OOM conditions.
52 //
53 // The algorithm used favors killing tabs that are not selected, not pinned,
54 // and have been idle for longest, in that order of priority.
55 //
56 // On Chrome OS (via the delegate), the kernel (via /proc/<pid>/oom_score_adj)
57 // will be informed of each renderer's score, which is based on the status, so
58 // in case Chrome is not able to relieve the pressure quickly enough and the
59 // kernel is forced to kill processes, it will be able to do so using the same
60 // algorithm as the one used here.
61 //
62 // Note that the browser tests are only active for platforms that use
63 // TabManager (CrOS only for now) and need to be adjusted accordingly if
64 // support for new platforms is added.
65 class TabManager : public TabStripModelObserver {
66 public:
67 // Needs to be public for DEFINE_WEB_CONTENTS_USER_DATA_KEY.
68 class WebContentsData;
69
70 TabManager();
71 ~TabManager() override;
72
73 // Number of discard events since Chrome started.
74 int discard_count() const { return discard_count_; }
75
76 // See member comment.
77 bool recent_tab_discard() const { return recent_tab_discard_; }
78
79 // Start/Stop the Tab Manager.
80 void Start();
81 void Stop();
82
83 // Returns the list of the stats for all renderers. Must be called on the UI
84 // thread. The returned list is sorted by reversed importance.
85 TabStatsList GetTabStats() const;
86
87 // Returns true if |contents| is currently discarded.
88 bool IsTabDiscarded(content::WebContents* contents) const;
89
90 // Goes through a list of checks to see if a tab is allowed to be discarded by
91 // the automatic tab discarding mechanism. Note that this is not used when
92 // discarding a particular tab from about:discards.
93 bool CanDiscardTab(int64_t target_web_contents_id) const;
94
95 // Discards a tab to free the memory occupied by its renderer. The tab still
96 // exists in the tab-strip; clicking on it will reload it.
97 void DiscardTab();
98
99 // Discards a tab with the given unique ID. The tab still exists in the
100 // tab-strip; clicking on it will reload it. Returns null if the tab cannot
101 // be found or cannot be discarded. Otherwise returns the new web_contents
102 // of the discarded tab.
103 content::WebContents* DiscardTabById(int64_t target_web_contents_id);
104
105 // Method used by the extensions API to discard tabs. If |contents| is null,
106 // discards the least important tab using DiscardTab(). Otherwise discards
107 // the given contents. Returns the new web_contents or null if no tab
108 // was discarded.
109 content::WebContents* DiscardTabByExtension(content::WebContents* contents);
110
111 // Log memory statistics for the running processes, then discards a tab.
112 // Tab discard happens sometime later, as collecting the statistics touches
113 // multiple threads and takes time.
114 void LogMemoryAndDiscardTab();
115
116 // Log memory statistics for the running processes, then call the callback.
117 void LogMemory(const std::string& title, const base::Closure& callback);
118
119 // Used to set the test TickClock, which then gets used by NowTicks(). See
120 // |test_tick_clock_| for more details.
121 void set_test_tick_clock(base::TickClock* test_tick_clock);
122
123 // Returns the list of the stats for all renderers. Must be called on the UI
124 // thread.
125 TabStatsList GetUnsortedTabStats() const;
126
127 void AddObserver(TabManagerObserver* observer);
128 void RemoveObserver(TabManagerObserver* observer);
129
130 // Used in tests to change the protection time of the tabs.
131 void set_minimum_protection_time_for_tests(
132 base::TimeDelta minimum_protection_time);
133
134 // Returns the auto-discardable state of the tab. When true, the tab is
135 // eligible to be automatically discarded when critical memory pressure hits,
136 // otherwise the tab is ignored and will never be automatically discarded.
137 // Note that this property doesn't block the discarding of the tab via other
138 // methods (about:discards for instance).
139 bool IsTabAutoDiscardable(content::WebContents* contents) const;
140
141 // Sets/clears the auto-discardable state of the tab.
142 void SetTabAutoDiscardableState(content::WebContents* contents, bool state);
143
144 // Returns true when a given renderer can be purged if the specified
145 // renderer is eligible for purging.
146 // TODO(tasak): rename this to CanPurgeBackgroundedRenderer.
147 bool CanSuspendBackgroundedRenderer(int render_process_id) const;
148
149 // Returns true if |first| is considered less desirable to be killed than
150 // |second|.
151 static bool CompareTabStats(const TabStats& first, const TabStats& second);
152
153 // Returns a unique ID for a WebContents. Do not cast back to a pointer, as
154 // the WebContents could be deleted if the user closed the tab.
155 static int64_t IdFromWebContents(content::WebContents* web_contents);
156
157 private:
158 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, PurgeBackgroundRenderer);
159 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ActivateTabResetPurgeState);
160 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ShouldPurgeAtDefaultTime);
161 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, DefaultTimeToPurgeInCorrectRange);
162 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, AutoDiscardable);
163 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, CanOnlyDiscardOnce);
164 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ChildProcessNotifications);
165 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, Comparator);
166 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, DiscardedTabKeepsLastActiveTime);
167 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, DiscardWebContentsAt);
168 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, InvalidOrEmptyURL);
169 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsInternalPage);
170 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OomPressureListener);
171 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectPDFPages);
172 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectRecentlyUsedTabs);
173 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectVideoTabs);
174 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ReloadDiscardedTabContextMenu);
175 FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabManagerBasics);
176
177 // The time of the first purging after a renderer is backgrounded.
178 // The initial value was chosen because most of users activate backgrounded
179 // tabs within 30 minutes. (c.f. Tabs.StateTransfer.Time_Inactive_Active)
180 static constexpr base::TimeDelta kDefaultMinTimeToPurge =
181 base::TimeDelta::FromMinutes(30);
182
183 // The min/max time to purge ratio. The max time to purge is set to be
184 // min time to purge times this value.
185 const int kMinMaxTimeToPurgeRatio = 2;
186
187 // This is needed so WebContentsData can call OnDiscardedStateChange, and
188 // can use PurgeState.
189 friend class WebContentsData;
190
191 // Finds TabStripModel which has a WebContents whose id is the given
192 // web_contents_id, and returns the WebContents index and the TabStripModel.
193 int FindTabStripModelById(int64_t target_web_contents_id,
194 TabStripModel** model) const;
195
196 // Called by WebContentsData whenever the discard state of a WebContents
197 // changes, so that observers can be informed.
198 void OnDiscardedStateChange(content::WebContents* contents,
199 bool is_discarded);
200
201 // Called by WebContentsData whenever the auto-discardable state of a
202 // WebContents changes, so that observers can be informed.
203 void OnAutoDiscardableStateChange(content::WebContents* contents,
204 bool is_auto_discardable);
205
206 static void PurgeMemoryAndDiscardTab();
207
208 // Returns true if the |url| represents an internal Chrome web UI page that
209 // can be easily reloaded and hence makes a good choice to discard.
210 static bool IsInternalPage(const GURL& url);
211
212 // Records UMA histogram statistics for a tab discard. Record statistics for
213 // user triggered discards via chrome://discards/ because that allows to
214 // manually test the system.
215 void RecordDiscardStatistics();
216
217 // Record whether an out of memory occured during a recent time interval. This
218 // allows the normalization of low memory statistics versus usage.
219 void RecordRecentTabDiscard();
220
221 // Purges data structures in the browser that can be easily recomputed.
222 void PurgeBrowserMemory();
223
224 // Returns the number of tabs open in all browser instances.
225 int GetTabCount() const;
226
227 // Adds all the stats of the tabs to |stats_list|.
228 void AddTabStats(TabStatsList* stats_list) const;
229
230 // Adds all the stats of the tabs in |tab_strip_model| into |stats_list|.
231 // If |active_model| is true, consider its first tab as being active.
232 void AddTabStats(const TabStripModel* model,
233 bool is_app,
234 bool active_model,
235 TabStatsList* stats_list) const;
236
237 // Callback for when |update_timer_| fires. Takes care of executing the tasks
238 // that need to be run periodically (see comment in implementation).
239 void UpdateTimerCallback();
240
241 // Returns WebContents whose contents id matches the given tab_contents_id.
242 content::WebContents* GetWebContentsById(int64_t tab_contents_id) const;
243
244 // Returns a random time-to-purge whose min value is min_time_to_purge and max
245 // value is min_time_to_purge * kMinMaxTimeToPurgeRatio.
246 base::TimeDelta GetTimeToPurge(base::TimeDelta min_time_to_purge) const;
247
248 // Returns true if the tab specified by |content| is now eligible to have
249 // its memory purged.
250 bool ShouldPurgeNow(content::WebContents* content) const;
251
252 // Purges renderers in backgrounded tabs if the following conditions are
253 // satisfied:
254 // - the renderers are not purged yet,
255 // - the renderers are not playing media,
256 // (CanPurgeBackgroundedRenderer returns true)
257 // - the renderers are left inactive and background for time-to-purge.
258 // If renderers are purged, their internal states become 'purged'.
259 // The state is reset to be 'not purged' only when they are activated
260 // (=ActiveTabChanged is invoked).
261 void PurgeBackgroundedTabsIfNeeded();
262
263 // Does the actual discard by destroying the WebContents in |model| at |index|
264 // and replacing it by an empty one. Returns the new WebContents or NULL if
265 // the operation fails (return value used only in testing).
266 content::WebContents* DiscardWebContentsAt(int index, TabStripModel* model);
267
268 // Called by the memory pressure listener when the memory pressure rises.
269 void OnMemoryPressure(
270 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
271
272 // TabStripModelObserver overrides.
273 void TabChangedAt(content::WebContents* contents,
274 int index,
275 TabChangeType change_type) override;
276 void ActiveTabChanged(content::WebContents* old_contents,
277 content::WebContents* new_contents,
278 int index,
279 int reason) override;
280 void TabInsertedAt(TabStripModel* tab_strip_model,
281 content::WebContents* contents,
282 int index,
283 bool foreground) override;
284
285 // Returns true if the tab is currently playing audio or has played audio
286 // recently, or if the tab is currently accessing the camera, microphone or
287 // mirroring the display.
288 bool IsMediaTab(content::WebContents* contents) const;
289
290 // Returns the WebContentsData associated with |contents|. Also takes care of
291 // creating one if needed.
292 WebContentsData* GetWebContentsData(content::WebContents* contents) const;
293
294 // Returns either the system's clock or the test clock. See |test_tick_clock_|
295 // for more details.
296 base::TimeTicks NowTicks() const;
297
298 // Implementation of DiscardTab. Returns null if no tab was discarded.
299 // Otherwise returns the new web_contents of the discarded tab.
300 content::WebContents* DiscardTabImpl();
301
302 // Returns true if tabs can be discarded only once.
303 bool CanOnlyDiscardOnce() const;
304
305 // Timer to periodically update the stats of the renderers.
306 base::RepeatingTimer update_timer_;
307
308 // Timer to periodically report whether a tab has been discarded since the
309 // last time the timer has fired.
310 base::RepeatingTimer recent_tab_discard_timer_;
311
312 // A listener to global memory pressure events.
313 std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
314
315 // Wall-clock time when the priority manager started running.
316 base::TimeTicks start_time_;
317
318 // Wall-clock time of last tab discard during this browsing session, or 0 if
319 // no discard has happened yet.
320 base::TimeTicks last_discard_time_;
321
322 // Wall-clock time of last priority adjustment, used to correct the above
323 // times for discontinuities caused by suspend/resume.
324 base::TimeTicks last_adjust_time_;
325
326 // Number of times a tab has been discarded, for statistics.
327 int discard_count_;
328
329 // Whether a tab discard event has occurred during the last time interval,
330 // used for statistics normalized by usage.
331 bool recent_tab_discard_;
332
333 // Whether a tab can only ever discarded once.
334 bool discard_once_;
335
336 // This allows protecting tabs for a certain amount of time after being
337 // backgrounded.
338 base::TimeDelta minimum_protection_time_;
339
340 // A backgrounded renderer will be purged when this time passes.
341 base::TimeDelta min_time_to_purge_;
342
343 #if defined(OS_CHROMEOS)
344 std::unique_ptr<TabManagerDelegate> delegate_;
345 #endif
346
347 // Responsible for automatically registering this class as an observer of all
348 // TabStripModels. Automatically tracks browsers as they come and go.
349 BrowserTabStripTracker browser_tab_strip_tracker_;
350
351 // Pointer to a test clock. If this is set, NowTicks() returns the value of
352 // this test clock. Otherwise it returns the system clock's value.
353 base::TickClock* test_tick_clock_;
354
355 // Injected tab strip models. Allows this to be tested end-to-end without
356 // requiring a full browser environment. If specified these tab strips will be
357 // crawled as the authoritative source of tabs, otherwise the BrowserList and
358 // associated Browser objects are crawled. The first of these is considered to
359 // be the 'active' tab strip model.
360 // TODO(chrisha): Factor out tab-strip model enumeration to a helper class,
361 // and make a delegate that centralizes all testing seams.
362 using TestTabStripModel = std::pair<const TabStripModel*, bool>;
363 std::vector<TestTabStripModel> test_tab_strip_models_;
364
365 // List of observers that will receive notifications on state changes.
366 base::ObserverList<TabManagerObserver> observers_;
367
368 // Weak pointer factory used for posting delayed tasks.
369 base::WeakPtrFactory<TabManager> weak_ptr_factory_;
370
371 DISALLOW_COPY_AND_ASSIGN(TabManager);
372 };
373
374 } // namespace memory
375
376 #endif // CHROME_BROWSER_MEMORY_TAB_MANAGER_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698