| // Copyright (c) 2011 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_PRERENDER_PRERENDER_MANAGER_H_ |
| #define CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_ |
| #pragma once |
| |
| #include <list> |
| #include <map> |
| #include <vector> |
| |
| #include "base/hash_tables.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/scoped_vector.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/task.h" |
| #include "base/threading/non_thread_safe.h" |
| #include "base/time.h" |
| #include "base/timer.h" |
| #include "chrome/browser/prerender/prerender_config.h" |
| #include "chrome/browser/prerender/prerender_contents.h" |
| #include "chrome/browser/prerender/prerender_origin.h" |
| #include "googleurl/src/gurl.h" |
| |
| class Profile; |
| class TabContents; |
| |
| #if defined(COMPILER_GCC) |
| |
| namespace __gnu_cxx { |
| template <> |
| struct hash<TabContents*> { |
| std::size_t operator()(TabContents* value) const { |
| return reinterpret_cast<std::size_t>(value); |
| } |
| }; |
| } |
| |
| #endif |
| |
| namespace prerender { |
| |
| class PrerenderHistory; |
| class PrerenderTracker; |
| |
| // PrerenderManager is responsible for initiating and keeping prerendered |
| // views of webpages. All methods must be called on the UI thread unless |
| // indicated otherwise. |
| class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>, |
| public base::NonThreadSafe { |
| public: |
| // PrerenderManagerMode is used in a UMA_HISTOGRAM, so please do not |
| // add in the middle. |
| enum PrerenderManagerMode { |
| PRERENDER_MODE_DISABLED, |
| PRERENDER_MODE_ENABLED, |
| PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP, |
| PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP, |
| PRERENDER_MODE_MAX |
| }; |
| |
| // One or more of these flags must be passed to ClearData() to specify just |
| // what data to clear. See function declaration for more information. |
| enum ClearFlags { |
| CLEAR_PRERENDER_CONTENTS = 0x1 << 0, |
| CLEAR_PRERENDER_HISTORY = 0x1 << 1, |
| CLEAR_MAX = 0x1 << 2 |
| }; |
| |
| // ID indicating that no experiment is active. |
| static const uint8 kNoExperiment = 0; |
| |
| // Owned by a Profile object for the lifetime of the profile. |
| PrerenderManager(Profile* profile, PrerenderTracker* prerender_tracker); |
| |
| virtual ~PrerenderManager(); |
| |
| // Entry points for adding prerenders. |
| |
| // Adds a prerender for |url| if valid. |process_id| and |route_id| identify |
| // the RenderViewHost that the prerender request came from and are used to |
| // set the initial window size of the RenderViewHost used for prerendering. |
| // Returns true if the URL was added, false if it was not. |
| // If the RenderViewHost source is itself prerendering, the prerender is added |
| // as a pending prerender. |
| bool AddPrerenderFromLinkRelPrerender(int process_id, int route_id, |
| const GURL& url, const GURL& referrer); |
| |
| // Adds a prerender for |url| if valid. As the prerender request is coming |
| // from a source without a RenderViewHost (ie, the omnibox) we don't have a |
| // child or route id, or a referrer. This method uses sensible values for |
| // those. |
| bool AddPrerenderFromOmnibox(const GURL& url); |
| |
| // Destroy all prerenders for the given child route id pair and assign a final |
| // status to them. |
| virtual void DestroyPrerenderForRenderView(int process_id, int view_id, |
| FinalStatus final_status); |
| |
| // For a given TabContents that wants to navigate to the URL supplied, |
| // determines whether a prerendered version of the URL can be used, |
| // and substitutes the prerendered RVH into the TabContents. Returns |
| // whether or not a prerendered RVH could be used or not. |
| bool MaybeUsePrerenderedPage(TabContents* tab_contents, |
| const GURL& url, |
| bool has_opener_set); |
| |
| // Moves a PrerenderContents to the pending delete list from the list of |
| // active prerenders when prerendering should be cancelled. |
| void MoveEntryToPendingDelete(PrerenderContents* entry); |
| |
| // Retrieves the PrerenderContents object for the specified URL, if it |
| // has been prerendered. The caller will then have ownership of the |
| // PrerenderContents object and is responsible for freeing it. |
| // Returns NULL if the specified URL has not been prerendered. |
| PrerenderContents* GetEntry(const GURL& url); |
| |
| // Identical to GetEntry, with one exception: |
| // The TabContents specified indicates the TC in which to swap the |
| // prerendering into. If the TabContents specified is the one |
| // to doing the prerendered itself, will return NULL. |
| PrerenderContents* GetEntryButNotSpecifiedTC(const GURL& url, |
| TabContents* tc); |
| |
| // Records the perceived page load time for a page - effectively the time from |
| // when the user navigates to a page to when it finishes loading. The actual |
| // load may have started prior to navigation due to prerender hints. |
| // This must be called on the UI thread. |
| static void RecordPerceivedPageLoadTime( |
| base::TimeDelta perceived_page_load_time, |
| TabContents* tab_contents); |
| |
| // Returns whether prerendering is currently enabled for this manager. |
| // Must be called on the UI thread. |
| bool is_enabled() const; |
| |
| // Set whether prerendering is currently enabled for this manager. |
| // Must be called on the UI thread. |
| // If |enabled| is false, existing prerendered pages will still persist until |
| // they time out, but new ones will not be generated. |
| void set_enabled(bool enabled); |
| |
| static PrerenderManagerMode GetMode(); |
| static void SetMode(PrerenderManagerMode mode); |
| static bool IsPrerenderingPossible(); |
| static bool IsControlGroup(); |
| |
| // Query the list of current prerender pages to see if the given tab contents |
| // is prerendering a page. |
| bool IsTabContentsPrerendering(TabContents* tab_contents) const; |
| |
| // Maintaining and querying the set of TabContents belonging to this |
| // PrerenderManager that are currently showing prerendered pages. |
| void MarkTabContentsAsPrerendered(TabContents* tab_contents); |
| void MarkTabContentsAsWouldBePrerendered(TabContents* tab_contents); |
| void MarkTabContentsAsNotPrerendered(TabContents* tab_contents); |
| bool IsTabContentsPrerendered(TabContents* tab_contents) const; |
| bool WouldTabContentsBePrerendered(TabContents* tab_contents) const; |
| bool IsOldRenderViewHost(const RenderViewHost* render_view_host) const; |
| |
| // Checks whether navigation to the provided URL has occured in a visible |
| // tab recently. |
| bool HasRecentlyBeenNavigatedTo(const GURL& url); |
| |
| // Returns true if the method given is invalid for prerendering. |
| static bool IsValidHttpMethod(const std::string& method); |
| |
| // Returns a Value object containing the active pages being prerendered, and |
| // a history of pages which were prerendered. The caller is responsible for |
| // deleting the return value. |
| base::Value* GetAsValue() const; |
| |
| // Clears the data indicated by which bits of clear_flags are set. |
| // |
| // If the CLEAR_PRERENDER_CONTENTS bit is set, all active prerenders are |
| // cancelled and then deleted, and any TabContents queued for destruction are |
| // destroyed as well. |
| // |
| // If the CLEAR_PRERENDER_HISTORY bit is set, the prerender history is |
| // cleared, including any entries newly created by destroying them in |
| // response to the CLEAR_PRERENDER_CONTENTS flag. |
| // |
| // Intended to be used when clearing the cache or history. |
| void ClearData(int clear_flags); |
| |
| // Record a final status of a prerendered page in a histogram. |
| void RecordFinalStatus(Origin origin, |
| uint8 experiment_id, |
| FinalStatus final_status) const; |
| |
| const Config& config() const { return config_; } |
| Config& mutable_config() { return config_; } |
| |
| protected: |
| // Test that needs needs access to internal functions. |
| FRIEND_TEST_ALL_PREFIXES(PrerenderManagerTest, ExpireTest); |
| FRIEND_TEST_ALL_PREFIXES(PrerenderManagerTest, ExtractURLInQueryStringTest); |
| |
| struct PendingContentsData; |
| |
| void SetPrerenderContentsFactory( |
| PrerenderContents::Factory* prerender_contents_factory); |
| |
| PendingContentsData* FindPendingEntry(const GURL& url); |
| |
| private: |
| // Test that needs needs access to internal functions. |
| friend class PrerenderBrowserTest; |
| |
| friend class base::RefCountedThreadSafe<PrerenderManager>; |
| |
| struct PrerenderContentsData; |
| struct NavigationRecord; |
| |
| class OnCloseTabContentsDeleter; |
| |
| // Adds a prerender for |url| from referrer |referrer| initiated from the |
| // RenderViewHost specified by |child_route_id_pair|. The |origin| specifies |
| // how the prerender was added. |
| bool AddPrerender( |
| Origin origin, |
| const std::pair<int, int>& child_route_id_pair, |
| const GURL& url, |
| const GURL& referrer); |
| |
| // Adds a pending preload issued by the prerendering RenderView identified by |
| // |child_route_id_pair|. If and when that prerendering RenderView is used, |
| // the specified prerender will start. |
| void AddPendingPrerender(Origin origin, |
| const std::pair<int, int>& child_route_id_pair, |
| const GURL& url, |
| const GURL& referrer); |
| |
| // Starts scheduling periodic cleanups. |
| void StartSchedulingPeriodicCleanups(); |
| // Stops scheduling periodic cleanups if they're no longer needed. |
| void MaybeStopSchedulingPeriodicCleanups(); |
| |
| // Deletes stale and cancelled prerendered PrerenderContents, as well as |
| // TabContents that have been replaced by prerendered TabContents. |
| // Also identifies and kills PrerenderContents that use too much |
| // resources. |
| void PeriodicCleanup(); |
| |
| // Posts a task to call PeriodicCleanup. Results in quicker destruction of |
| // objects. If |this| is deleted before the task is run, the task will |
| // automatically be cancelled. |
| void PostCleanupTask(); |
| |
| bool IsPrerenderElementFresh(const base::Time start) const; |
| void DeleteOldEntries(); |
| virtual base::Time GetCurrentTime() const; |
| virtual base::TimeTicks GetCurrentTimeTicks() const; |
| virtual PrerenderContents* CreatePrerenderContents(const GURL& url, |
| const GURL& referrer, |
| Origin origin, |
| uint8 experiment_id); |
| |
| // Checks if the PrerenderContents has been added to the pending delete list. |
| bool IsPendingDelete(PrerenderContents* entry) const; |
| |
| // Deletes any PrerenderContents that have been added to the pending delete |
| // list. |
| void DeletePendingDeleteEntries(); |
| |
| // Finds the specified PrerenderContents and returns it, if it exists. |
| // Returns NULL otherwise. Unlike GetEntry, the PrerenderManager maintains |
| // ownership of the PrerenderContents. |
| PrerenderContents* FindEntry(const GURL& url); |
| |
| // Returns the iterator to the PrerenderContentsData entry that is being |
| // prerendered from the given child route id pair. |
| std::list<PrerenderContentsData>::iterator |
| FindPrerenderContentsForChildRouteIdPair( |
| const std::pair<int, int>& child_route_id_pair); |
| |
| // Returns whether the PrerenderManager is currently within the prerender |
| // window - effectively, up to 30 seconds after a prerender tag has been |
| // observed. |
| bool WithinWindow() const; |
| |
| // Called when removing a preload to ensure we clean up any pending preloads |
| // that might remain in the map. |
| void RemovePendingPrerender(PrerenderContents* entry); |
| |
| bool DoesRateLimitAllowPrerender() const; |
| |
| // Deletes old TabContents that have been replaced by prerendered ones. This |
| // is needed because they're replaced in a callback from the old TabContents, |
| // so cannot immediately be deleted. |
| void DeleteOldTabContents(); |
| |
| // Cleans up old NavigationRecord's. |
| void CleanUpOldNavigations(); |
| |
| // Arrange for the given tab contents to be deleted asap. If deleter is not |
| // NULL, deletes that as well. |
| void ScheduleDeleteOldTabContents(TabContentsWrapper* tab, |
| OnCloseTabContentsDeleter* deleter); |
| |
| // Adds to the history list. |
| void AddToHistory(PrerenderContents* contents); |
| |
| // Records that some visible tab navigated (or was redirected) to the |
| // provided URL. |
| void RecordNavigation(const GURL& url); |
| |
| // Returns a new Value representing the pages currently being prerendered. The |
| // caller is responsible for delete'ing the return value. |
| base::Value* GetActivePrerendersAsValue() const; |
| |
| // Destroys all pending prerenders using FinalStatus. Also deletes them as |
| // well as any swapped out TabContents queued for destruction. |
| // Used both on destruction, and when clearing the browing history. |
| void DestroyAllContents(FinalStatus final_status); |
| |
| // Records the time from when a page starts prerendering to when the user |
| // navigates to it. This must be called on the UI thread. |
| void RecordTimeUntilUsed(base::TimeDelta time_until_used); |
| |
| // Composes a histogram name based on a histogram type. |
| std::string ComposeHistogramName(const std::string& prefix_type, |
| const std::string& name) const; |
| |
| // Returns the histogram name for a given origin and experiment. |
| std::string GetHistogramName(Origin origin, uint8 experiment_id, |
| const std::string& name) const; |
| // Returns the histogram name for the current window. |
| std::string GetDefaultHistogramName(const std::string& name) const; |
| // Returns the current experiment. |
| uint8 GetCurrentExperimentId() const; |
| // Returns the current origin. |
| Origin GetCurrentOrigin() const; |
| // Returns whether or not there is currently an origin/experiment wash. |
| bool IsOriginExperimentWash() const; |
| |
| // The configuration. |
| Config config_; |
| |
| // Specifies whether prerendering is currently enabled for this |
| // manager. The value can change dynamically during the lifetime |
| // of the PrerenderManager. |
| bool enabled_; |
| |
| // The profile that owns this PrerenderManager. |
| Profile* profile_; |
| |
| PrerenderTracker* prerender_tracker_; |
| |
| // List of prerendered elements. |
| std::list<PrerenderContentsData> prerender_list_; |
| |
| // List of recent navigations in this profile, sorted by ascending |
| // navigate_time_. |
| std::list<NavigationRecord> navigations_; |
| |
| // List of prerender elements to be deleted |
| std::list<PrerenderContents*> pending_delete_list_; |
| |
| // Set of TabContents which are currently displaying a prerendered page. |
| base::hash_set<TabContents*> prerendered_tab_contents_set_; |
| |
| // Set of TabContents which would be displaying a prerendered page |
| // (for the control group). |
| base::hash_set<TabContents*> would_be_prerendered_tab_contents_set_; |
| |
| // Map of child/route id pairs to pending prerender data. |
| typedef std::map<std::pair<int, int>, std::vector<PendingContentsData> > |
| PendingPrerenderList; |
| PendingPrerenderList pending_prerender_list_; |
| |
| scoped_ptr<PrerenderContents::Factory> prerender_contents_factory_; |
| |
| static PrerenderManagerMode mode_; |
| |
| // An integer indicating a Prerendering Experiment being currently conducted. |
| // (The last experiment ID seen). |
| uint8 last_experiment_id_; |
| |
| // Origin of the last prerender seen. |
| Origin last_origin_; |
| |
| // A boolean indicating that we have recently encountered a combination of |
| // different experiments and origins, making an attribution of PPLT's to |
| // experiments / origins impossible. |
| bool origin_experiment_wash_; |
| |
| // The time when we last saw a prerender request coming from a renderer. |
| // This is used to record perceived PLT's for a certain amount of time |
| // from the point that we last saw a <link rel=prerender> tag. |
| base::TimeTicks last_prerender_seen_time_; |
| |
| // A count of how many prerenders we do per session. Initialized to 0 then |
| // incremented and emitted to a histogram on each successful prerender. |
| static int prerenders_per_session_count_; |
| |
| // RepeatingTimer to perform periodic cleanups of pending prerendered |
| // pages. |
| base::RepeatingTimer<PrerenderManager> repeating_timer_; |
| |
| // Track time of last prerender to limit prerender spam. |
| base::TimeTicks last_prerender_start_time_; |
| |
| std::list<TabContentsWrapper*> old_tab_contents_list_; |
| |
| // Cancels pending tasks on deletion. |
| ScopedRunnableMethodFactory<PrerenderManager> runnable_method_factory_; |
| |
| ScopedVector<OnCloseTabContentsDeleter> on_close_tab_contents_deleters_; |
| |
| scoped_ptr<PrerenderHistory> prerender_history_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PrerenderManager); |
| }; |
| |
| } // namespace prerender |
| |
| #endif // CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_ |