| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_MEMORY_TAB_MANAGER_H_ |
| #define CHROME_BROWSER_MEMORY_TAB_MANAGER_H_ |
| |
| #include <stdint.h> |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "base/compiler_specific.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/macros.h" |
| #include "base/memory/memory_pressure_listener.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/strings/string16.h" |
| #include "base/timer/timer.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/memory/tab_stats.h" |
| #include "chrome/browser/ui/browser_tab_strip_tracker.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" |
| |
| class BrowserList; |
| class GURL; |
| |
| namespace base { |
| class TickClock; |
| } |
| |
| namespace content { |
| class WebContents; |
| } |
| |
| namespace memory { |
| |
| #if defined(OS_CHROMEOS) |
| class TabManagerDelegate; |
| #endif |
| |
| // The TabManager periodically updates (see |
| // |kAdjustmentIntervalSeconds| in the source) the status of renderers |
| // which are then used by the algorithm embedded here for priority in being |
| // killed upon OOM conditions. |
| // |
| // The algorithm used favors killing tabs that are not selected, not pinned, |
| // and have been idle for longest, in that order of priority. |
| // |
| // On Chrome OS (via the delegate), the kernel (via /proc/<pid>/oom_score_adj) |
| // will be informed of each renderer's score, which is based on the status, so |
| // in case Chrome is not able to relieve the pressure quickly enough and the |
| // kernel is forced to kill processes, it will be able to do so using the same |
| // algorithm as the one used here. |
| // |
| // Note that the browser tests are only active for platforms that use |
| // TabManager (CrOS only for now) and need to be adjusted accordingly if |
| // support for new platforms is added. |
| class TabManager : public TabStripModelObserver { |
| public: |
| // Needs to be public for DEFINE_WEB_CONTENTS_USER_DATA_KEY. |
| class WebContentsData; |
| |
| TabManager(); |
| ~TabManager() override; |
| |
| // Number of discard events since Chrome started. |
| int discard_count() const { return discard_count_; } |
| |
| // See member comment. |
| bool recent_tab_discard() const { return recent_tab_discard_; } |
| |
| // Start/Stop the Tab Manager. |
| void Start(); |
| void Stop(); |
| |
| // Returns the list of the stats for all renderers. Must be called on the UI |
| // thread. |
| TabStatsList GetTabStats(); |
| |
| // Returns true if |contents| is currently discarded. |
| bool IsTabDiscarded(content::WebContents* contents) const; |
| |
| // Discards a tab to free the memory occupied by its renderer. The tab still |
| // exists in the tab-strip; clicking on it will reload it. Returns true if it |
| // successfully found a tab and discarded it. |
| bool DiscardTab(); |
| |
| // Discards a tab with the given unique ID. The tab still exists in the |
| // tab-strip; clicking on it will reload it. Returns true if it successfully |
| // found a tab and discarded it. |
| content::WebContents* DiscardTabById(int64_t target_web_contents_id); |
| |
| // Log memory statistics for the running processes, then discards a tab. |
| // Tab discard happens sometime later, as collecting the statistics touches |
| // multiple threads and takes time. |
| void LogMemoryAndDiscardTab(); |
| |
| // Log memory statistics for the running processes, then call the callback. |
| void LogMemory(const std::string& title, const base::Closure& callback); |
| |
| // Used to set the test TickClock, which then gets used by NowTicks(). See |
| // |test_tick_clock_| for more details. |
| void set_test_tick_clock(base::TickClock* test_tick_clock); |
| |
| private: |
| FRIEND_TEST_ALL_PREFIXES(TabManagerTest, Comparator); |
| FRIEND_TEST_ALL_PREFIXES(TabManagerTest, DiscardedTabKeepsLastActiveTime); |
| FRIEND_TEST_ALL_PREFIXES(TabManagerTest, DiscardWebContentsAt); |
| FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsInternalPage); |
| FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectRecentlyUsedTabs); |
| FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ReloadDiscardedTabContextMenu); |
| FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabManagerBasics); |
| |
| static void PurgeMemoryAndDiscardTab(); |
| |
| // Returns true if the |url| represents an internal Chrome web UI page that |
| // can be easily reloaded and hence makes a good choice to discard. |
| static bool IsInternalPage(const GURL& url); |
| |
| // Records UMA histogram statistics for a tab discard. Record statistics for |
| // user triggered discards via chrome://discards/ because that allows to |
| // manually test the system. |
| void RecordDiscardStatistics(); |
| |
| // Record whether an out of memory occured during a recent time interval. This |
| // allows the normalization of low memory statistics versus usage. |
| void RecordRecentTabDiscard(); |
| |
| // Purges data structures in the browser that can be easily recomputed. |
| void PurgeBrowserMemory(); |
| |
| // Returns the number of tabs open in all browser instances. |
| int GetTabCount() const; |
| |
| // Adds all the stats of the tabs to |stats_list|. |
| void AddTabStats(TabStatsList* stats_list); |
| |
| // Callback for when |update_timer_| fires. Takes care of executing the tasks |
| // that need to be run periodically (see comment in implementation). |
| void UpdateTimerCallback(); |
| |
| // Goes through a list of checks to see if a tab is allowed to be discarded by |
| // the automatic tab discarding mechanism. Note that this is not used when |
| // discarding a particular tab from about:discards. |
| bool CanDiscardTab(int64_t target_web_contents_id) const; |
| |
| // Does the actual discard by destroying the WebContents in |model| at |index| |
| // and replacing it by an empty one. Returns the new WebContents or NULL if |
| // the operation fails (return value used only in testing). |
| content::WebContents* DiscardWebContentsAt(int index, TabStripModel* model); |
| |
| // Called by the memory pressure listener when the memory pressure rises. |
| void OnMemoryPressure( |
| base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level); |
| |
| // TabStripModelObserver overrides. |
| void TabChangedAt(content::WebContents* contents, |
| int index, |
| TabChangeType change_type) override; |
| void ActiveTabChanged(content::WebContents* old_contents, |
| content::WebContents* new_contents, |
| int index, |
| int reason) override; |
| |
| // Returns true if the tab is currently playing audio or has played audio |
| // recently, or if the tab is currently accessing the camera, microphone or |
| // mirroring the display. |
| bool IsMediaTab(content::WebContents* contents) const; |
| |
| // Returns the WebContentsData associated with |contents|. Also takes care of |
| // creating one if needed. |
| WebContentsData* GetWebContentsData(content::WebContents* contents) const; |
| |
| // Returns true if |first| is considered less desirable to be killed than |
| // |second|. |
| static bool CompareTabStats(TabStats first, TabStats second); |
| |
| // Returns either the system's clock or the test clock. See |test_tick_clock_| |
| // for more details. |
| base::TimeTicks NowTicks() const; |
| |
| // Timer to periodically update the stats of the renderers. |
| base::RepeatingTimer update_timer_; |
| |
| // Timer to periodically report whether a tab has been discarded since the |
| // last time the timer has fired. |
| base::RepeatingTimer recent_tab_discard_timer_; |
| |
| // A listener to global memory pressure events. |
| scoped_ptr<base::MemoryPressureListener> memory_pressure_listener_; |
| |
| // Wall-clock time when the priority manager started running. |
| base::TimeTicks start_time_; |
| |
| // Wall-clock time of last tab discard during this browsing session, or 0 if |
| // no discard has happened yet. |
| base::TimeTicks last_discard_time_; |
| |
| // Wall-clock time of last priority adjustment, used to correct the above |
| // times for discontinuities caused by suspend/resume. |
| base::TimeTicks last_adjust_time_; |
| |
| // Number of times a tab has been discarded, for statistics. |
| int discard_count_; |
| |
| // Whether a tab discard event has occurred during the last time interval, |
| // used for statistics normalized by usage. |
| bool recent_tab_discard_; |
| |
| // Whether a tab can only ever discarded once. |
| bool discard_once_; |
| |
| // This allows protecting tabs for a certain amount of time after being |
| // backgrounded. |
| base::TimeDelta minimum_protection_time_; |
| |
| #if defined(OS_CHROMEOS) |
| scoped_ptr<TabManagerDelegate> delegate_; |
| #endif |
| |
| BrowserTabStripTracker browser_tab_strip_tracker_; |
| |
| // Pointer to a test clock. If this is set, NowTicks() returns the value of |
| // this test clock. Otherwise it returns the system clock's value. |
| base::TickClock* test_tick_clock_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TabManager); |
| }; |
| |
| } // namespace memory |
| |
| #endif // CHROME_BROWSER_MEMORY_TAB_MANAGER_H_ |