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