| // 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/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/time.h" |
| #include "base/timer.h" |
| #include "chrome/browser/prerender/prerender_contents.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 { |
| |
| // PrerenderManager is responsible for initiating and keeping prerendered |
| // views of webpages. |
| class PrerenderManager : public base::RefCountedThreadSafe<PrerenderManager> { |
| 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 |
| }; |
| |
| // Owned by a Profile object for the lifetime of the profile. |
| explicit PrerenderManager(Profile* profile); |
| |
| // Preloads the URL supplied. alias_urls indicates URLs that redirect |
| // to the same URL to be preloaded. Returns true if the URL was added, |
| // false if it was not. |
| bool AddPreload(const GURL& url, const std::vector<GURL>& alias_urls, |
| const GURL& referrer); |
| |
| void AddPendingPreload(const std::pair<int, int>& child_route_id_pair, |
| const GURL& url, |
| const std::vector<GURL>& alias_urls, |
| const GURL& referrer); |
| |
| // For a given TabContents that wants to navigate to the URL supplied, |
| // determines whether a preloaded 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 MaybeUsePreloadedPage(TabContents* tc, const GURL& url); |
| |
| // Allows PrerenderContents to remove itself when prerendering should |
| // be cancelled. |
| void RemoveEntry(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); |
| |
| // 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); |
| |
| // 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); |
| |
| base::TimeDelta max_prerender_age() const { return max_prerender_age_; } |
| void set_max_prerender_age(base::TimeDelta td) { max_prerender_age_ = td; } |
| unsigned int max_elements() const { return max_elements_; } |
| void set_max_elements(unsigned int num) { max_elements_ = num; } |
| |
| // 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(); |
| |
| // The following static method can be called from any thread, but will result |
| // in posting a task to the UI thread if we are not in the UI thread. |
| static void RecordPrefetchTagObserved(); |
| |
| // Maintaining and querying the set of TabContents belonging to this |
| // PrerenderManager that are currently showing prerendered pages. |
| void MarkTabContentsAsPrerendered(TabContents* tc); |
| void MarkTabContentsAsWouldBePrerendered(TabContents* tc); |
| void MarkTabContentsAsNotPrerendered(TabContents* tc); |
| bool IsTabContentsPrerendered(TabContents* tc) const; |
| bool WouldTabContentsBePrerendered(TabContents* tc) const; |
| |
| // Extracts a urlencoded URL stored in a url= query parameter from a URL |
| // supplied, if available, and stores it in alias_url. Returns whether or not |
| // the operation succeeded (i.e. a valid URL was found). |
| static bool MaybeGetQueryStringBasedAliasURL(const GURL& url, |
| GURL* alias_url); |
| |
| protected: |
| struct PendingContentsData; |
| |
| virtual ~PrerenderManager(); |
| |
| void SetPrerenderContentsFactory( |
| PrerenderContents::Factory* prerender_contents_factory); |
| bool rate_limit_enabled_; |
| |
| PendingContentsData* FindPendingEntry(const GURL& url); |
| |
| private: |
| // Test that needs needs access to internal functions. |
| friend class PrerenderBrowserTest; |
| |
| friend class base::RefCountedThreadSafe<PrerenderManager>; |
| |
| struct PrerenderContentsData; |
| |
| // Starts and stops scheduling periodic cleanups, respectively. |
| void StartSchedulingPeriodicCleanups(); |
| void StopSchedulingPeriodicCleanups(); |
| |
| // Deletes stale prerendered PrerenderContents. |
| // Also identifies and kills PrerenderContents that use too much |
| // resources. |
| void PeriodicCleanup(); |
| |
| 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 std::vector<GURL>& alias_urls, |
| const GURL& referrer); |
| |
| // 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); |
| |
| static bool WithinWindow(); |
| |
| static void RecordPrefetchTagObservedOnUIThread(); |
| |
| // Called when removing a preload to ensure we clean up any pending preloads |
| // that might remain in the map. |
| void RemovePendingPreload(PrerenderContents* entry); |
| |
| bool DoesRateLimitAllowPrerender() const; |
| |
| // Specifies whether prerendering is currently enabled for this |
| // manager. The value can change dynamically during the lifetime |
| // of the PrerenderManager. |
| bool enabled_; |
| |
| Profile* profile_; |
| |
| base::TimeDelta max_prerender_age_; |
| unsigned int max_elements_; |
| |
| // List of prerendered elements. |
| std::list<PrerenderContentsData> prerender_list_; |
| |
| // Set of TabContents which are currently displaying a prerendered page. |
| base::hash_set<TabContents*> prerendered_tc_set_; |
| |
| // Set of TabContents which would be displaying a prerendered page |
| // (for the control group). |
| base::hash_set<TabContents*> would_be_prerendered_tc_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_; |
| |
| // Default maximum permitted elements to prerender. |
| static const unsigned int kDefaultMaxPrerenderElements = 1; |
| |
| // Default maximum age a prerendered element may have, in seconds. |
| static const int kDefaultMaxPrerenderAgeSeconds = 20; |
| |
| // Time window for which we will record windowed PLT's from the last |
| // observed link rel=prefetch tag. |
| static const int kWindowDurationSeconds = 30; |
| |
| // Time interval at which periodic cleanups are performed. |
| static const int kPeriodicCleanupIntervalMs = 1000; |
| |
| // Time interval before a new prerender is allowed. |
| static const int kMinTimeBetweenPrerendersMs = 500; |
| |
| scoped_ptr<PrerenderContents::Factory> prerender_contents_factory_; |
| |
| static PrerenderManagerMode mode_; |
| |
| // The time when we last saw a prefetch 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=prefetch> tag. |
| // This static variable should only be modified on the UI thread. |
| static base::TimeTicks last_prefetch_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_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PrerenderManager); |
| }; |
| |
| } // prerender |
| |
| #endif // CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_ |