• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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_PRERENDER_PRERENDER_MANAGER_H_
6 #define CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_
7 #pragma once
8 
9 #include <list>
10 #include <map>
11 #include <vector>
12 
13 #include "base/hash_tables.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/time.h"
17 #include "base/timer.h"
18 #include "chrome/browser/prerender/prerender_contents.h"
19 #include "googleurl/src/gurl.h"
20 
21 class Profile;
22 class TabContents;
23 
24 #if defined(COMPILER_GCC)
25 
26 namespace __gnu_cxx {
27 template <>
28 struct hash<TabContents*> {
29   std::size_t operator()(TabContents* value) const {
30     return reinterpret_cast<std::size_t>(value);
31   }
32 };
33 }
34 
35 #endif
36 
37 namespace prerender {
38 
39 // PrerenderManager is responsible for initiating and keeping prerendered
40 // views of webpages.
41 class PrerenderManager : public base::RefCountedThreadSafe<PrerenderManager> {
42  public:
43   // PrerenderManagerMode is used in a UMA_HISTOGRAM, so please do not
44   // add in the middle.
45   enum PrerenderManagerMode {
46     PRERENDER_MODE_DISABLED,
47     PRERENDER_MODE_ENABLED,
48     PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP,
49     PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP,
50     PRERENDER_MODE_MAX
51   };
52 
53   // Owned by a Profile object for the lifetime of the profile.
54   explicit PrerenderManager(Profile* profile);
55 
56   // Preloads the URL supplied.  alias_urls indicates URLs that redirect
57   // to the same URL to be preloaded. Returns true if the URL was added,
58   // false if it was not.
59   bool AddPreload(const GURL& url, const std::vector<GURL>& alias_urls,
60                   const GURL& referrer);
61 
62   void AddPendingPreload(const std::pair<int, int>& child_route_id_pair,
63                          const GURL& url,
64                          const std::vector<GURL>& alias_urls,
65                          const GURL& referrer);
66 
67   // For a given TabContents that wants to navigate to the URL supplied,
68   // determines whether a preloaded version of the URL can be used,
69   // and substitutes the prerendered RVH into the TabContents.  Returns
70   // whether or not a prerendered RVH could be used or not.
71   bool MaybeUsePreloadedPage(TabContents* tc, const GURL& url);
72 
73   // Allows PrerenderContents to remove itself when prerendering should
74   // be cancelled.
75   void RemoveEntry(PrerenderContents* entry);
76 
77   // Retrieves the PrerenderContents object for the specified URL, if it
78   // has been prerendered.  The caller will then have ownership of the
79   // PrerenderContents object and is responsible for freeing it.
80   // Returns NULL if the specified URL has not been prerendered.
81   PrerenderContents* GetEntry(const GURL& url);
82 
83   // Records the perceived page load time for a page - effectively the time from
84   // when the user navigates to a page to when it finishes loading. The actual
85   // load may have started prior to navigation due to prerender hints.
86   // This must be called on the UI thread.
87   static void RecordPerceivedPageLoadTime(
88       base::TimeDelta perceived_page_load_time,
89       TabContents* tab_contents);
90 
91   // Records the time from when a page starts prerendering to when the user
92   // navigates to it. This must be called on the UI thread.
93   void RecordTimeUntilUsed(base::TimeDelta time_until_used);
94 
95   base::TimeDelta max_prerender_age() const { return max_prerender_age_; }
96   void set_max_prerender_age(base::TimeDelta td) { max_prerender_age_ = td; }
97   unsigned int max_elements() const { return max_elements_; }
98   void set_max_elements(unsigned int num) { max_elements_ = num; }
99 
100   // Returns whether prerendering is currently enabled for this manager.
101   // Must be called on the UI thread.
102   bool is_enabled() const;
103 
104   // Set whether prerendering is currently enabled for this manager.
105   // Must be called on the UI thread.
106   // If |enabled| is false, existing prerendered pages will still persist until
107   // they time out, but new ones will not be generated.
108   void set_enabled(bool enabled);
109 
110   static PrerenderManagerMode GetMode();
111   static void SetMode(PrerenderManagerMode mode);
112   static bool IsPrerenderingPossible();
113   static bool IsControlGroup();
114 
115   // The following static method can be called from any thread, but will result
116   // in posting a task to the UI thread if we are not in the UI thread.
117   static void RecordPrefetchTagObserved();
118 
119   // Maintaining and querying the set of TabContents belonging to this
120   // PrerenderManager that are currently showing prerendered pages.
121   void MarkTabContentsAsPrerendered(TabContents* tc);
122   void MarkTabContentsAsWouldBePrerendered(TabContents* tc);
123   void MarkTabContentsAsNotPrerendered(TabContents* tc);
124   bool IsTabContentsPrerendered(TabContents* tc) const;
125   bool WouldTabContentsBePrerendered(TabContents* tc) const;
126 
127   // Extracts a urlencoded URL stored in a url= query parameter from a URL
128   // supplied, if available, and stores it in alias_url.  Returns whether or not
129   // the operation succeeded (i.e. a valid URL was found).
130   static bool MaybeGetQueryStringBasedAliasURL(const GURL& url,
131                                                GURL* alias_url);
132 
133  protected:
134   struct PendingContentsData;
135 
136   virtual ~PrerenderManager();
137 
138   void SetPrerenderContentsFactory(
139       PrerenderContents::Factory* prerender_contents_factory);
140   bool rate_limit_enabled_;
141 
142   PendingContentsData* FindPendingEntry(const GURL& url);
143 
144  private:
145   // Test that needs needs access to internal functions.
146   friend class PrerenderBrowserTest;
147 
148   friend class base::RefCountedThreadSafe<PrerenderManager>;
149 
150   struct PrerenderContentsData;
151 
152   // Starts and stops scheduling periodic cleanups, respectively.
153   void StartSchedulingPeriodicCleanups();
154   void StopSchedulingPeriodicCleanups();
155 
156   // Deletes stale prerendered PrerenderContents.
157   // Also identifies and kills PrerenderContents that use too much
158   // resources.
159   void PeriodicCleanup();
160 
161   bool IsPrerenderElementFresh(const base::Time start) const;
162   void DeleteOldEntries();
163   virtual base::Time GetCurrentTime() const;
164   virtual base::TimeTicks GetCurrentTimeTicks() const;
165   virtual PrerenderContents* CreatePrerenderContents(
166       const GURL& url,
167       const std::vector<GURL>& alias_urls,
168       const GURL& referrer);
169 
170   // Finds the specified PrerenderContents and returns it, if it exists.
171   // Returns NULL otherwise.  Unlike GetEntry, the PrerenderManager maintains
172   // ownership of the PrerenderContents.
173   PrerenderContents* FindEntry(const GURL& url);
174 
175   static bool WithinWindow();
176 
177   static void RecordPrefetchTagObservedOnUIThread();
178 
179   // Called when removing a preload to ensure we clean up any pending preloads
180   // that might remain in the map.
181   void RemovePendingPreload(PrerenderContents* entry);
182 
183   bool DoesRateLimitAllowPrerender() const;
184 
185   // Specifies whether prerendering is currently enabled for this
186   // manager. The value can change dynamically during the lifetime
187   // of the PrerenderManager.
188   bool enabled_;
189 
190   Profile* profile_;
191 
192   base::TimeDelta max_prerender_age_;
193   unsigned int max_elements_;
194 
195   // List of prerendered elements.
196   std::list<PrerenderContentsData> prerender_list_;
197 
198   // Set of TabContents which are currently displaying a prerendered page.
199   base::hash_set<TabContents*> prerendered_tc_set_;
200 
201   // Set of TabContents which would be displaying a prerendered page
202   // (for the control group).
203   base::hash_set<TabContents*> would_be_prerendered_tc_set_;
204 
205   // Map of child/route id pairs to pending prerender data.
206   typedef std::map<std::pair<int, int>, std::vector<PendingContentsData> >
207       PendingPrerenderList;
208   PendingPrerenderList pending_prerender_list_;
209 
210   // Default maximum permitted elements to prerender.
211   static const unsigned int kDefaultMaxPrerenderElements = 1;
212 
213   // Default maximum age a prerendered element may have, in seconds.
214   static const int kDefaultMaxPrerenderAgeSeconds = 20;
215 
216   // Time window for which we will record windowed PLT's from the last
217   // observed link rel=prefetch tag.
218   static const int kWindowDurationSeconds = 30;
219 
220   // Time interval at which periodic cleanups are performed.
221   static const int kPeriodicCleanupIntervalMs = 1000;
222 
223   // Time interval before a new prerender is allowed.
224   static const int kMinTimeBetweenPrerendersMs = 500;
225 
226   scoped_ptr<PrerenderContents::Factory> prerender_contents_factory_;
227 
228   static PrerenderManagerMode mode_;
229 
230   // The time when we last saw a prefetch request coming from a renderer.
231   // This is used to record perceived PLT's for a certain amount of time
232   // from the point that we last saw a <link rel=prefetch> tag.
233   // This static variable should only be modified on the UI thread.
234   static base::TimeTicks last_prefetch_seen_time_;
235 
236   // A count of how many prerenders we do per session. Initialized to 0 then
237   // incremented and emitted to a histogram on each successful prerender.
238   static int prerenders_per_session_count_;
239 
240   // RepeatingTimer to perform periodic cleanups of pending prerendered
241   // pages.
242   base::RepeatingTimer<PrerenderManager> repeating_timer_;
243 
244   // Track time of last prerender to limit prerender spam.
245   base::TimeTicks last_prerender_start_time_;
246 
247   DISALLOW_COPY_AND_ASSIGN(PrerenderManager);
248 };
249 
250 }  // prerender
251 
252 #endif  // CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_
253