summaryrefslogtreecommitdiffstats
path: root/chrome/browser/prerender/prerender_manager.h
blob: 5577cebbcceaab657d52538000069c15f704a51b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
// 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/weak_ptr.h"
#include "base/threading/non_thread_safe.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 {

// Adds either a preload or a pending preload to the PrerenderManager.
// Must be called on the UI thread.
void HandlePrefetchTag(
    const base::WeakPtr<PrerenderManager>& prerender_manager,
    int render_process_id,
    int render_view_id,
    const GURL& url,
    const GURL& referrer,
    bool make_pending);

// Given a renderer process id and view id, this will destroy any preloads and
// pending preloads than are using or originated in the given render view.
// Must be called on the UI thread.
void DestroyPreloadForRenderView(
    const base::WeakPtr<PrerenderManager>& prerender_manager_weak_ptr,
    int render_process_id,
    int render_view_id,
    FinalStatus final_status);

// 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
  };

  // Owned by a Profile object for the lifetime of the profile.
  explicit PrerenderManager(Profile* profile);

  virtual ~PrerenderManager();

  // Preloads |url| if valid.  |child_route_id_pair| identifies the
  // RenderViewHost that the prerender request came from and is 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.
  bool AddPreload(
      const std::pair<int, int>& child_route_id_pair,
      const GURL& url,
      const GURL& referrer);

  void AddPendingPreload(const std::pair<int, int>& child_route_id_pair,
                         const GURL& url,
                         const GURL& referrer);

  // Destroy all preloads for the given child route id pair and assign a final
  // status to them.
  void DestroyPreloadForChildRouteIdPair(
      const std::pair<int, int>& child_route_id_pair,
      FinalStatus final_status);

  // 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* tab_contents, const GURL& url);
  bool MaybeUsePreloadedPageOld(TabContents* tab_contents, 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);

  // 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);

  // 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;
  void set_max_prerender_age(base::TimeDelta max_age);
  size_t max_prerender_memory_mb() const;
  void set_max_prerender_memory_mb(size_t prerender_memory_mb);
  unsigned int max_elements() const;
  void set_max_elements(unsigned int 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();

  // Records that a prefetch tag has been observed.
  void RecordPrefetchTagObserved();

  // 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;

  // 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);

  // Returns true if the method given is invalid for prerendering.
  static bool IsValidHttpMethod(const std::string& method);

 protected:
  struct PendingContentsData;

  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 scheduling periodic cleanups.
  void StartSchedulingPeriodicCleanups();
  // Stops scheduling periodic cleanups if they're no longer needed.
  void MaybeStopSchedulingPeriodicCleanups();

  // 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 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);

  // 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 prefetch 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 RemovePendingPreload(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();

  // 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_;
  // Maximum amount of memory, in megabytes, that a single PrerenderContents
  // can use before it's cancelled.
  size_t max_prerender_memory_mb_;
  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_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_;

  // 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.
  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_;

  std::list<TabContentsWrapper*> old_tab_contents_list_;

  DISALLOW_COPY_AND_ASSIGN(PrerenderManager);
};

}  // namespace prerender

#endif  // CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_