Revert 194484 "Add the LoggedIn Predictor, to detect which websi..."
[chromium-blink-merge.git] / chrome / browser / prerender / prerender_manager.h
blob9b0b7fc47fc7aba4c48667c7b728afcf82a5c756
1 // Copyright (c) 2012 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.
5 #ifndef CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_
6 #define CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_
8 #include <list>
9 #include <map>
10 #include <string>
11 #include <utility>
12 #include <vector>
14 #include "base/gtest_prod_util.h"
15 #include "base/hash_tables.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/memory/scoped_vector.h"
18 #include "base/memory/weak_ptr.h"
19 #include "base/threading/non_thread_safe.h"
20 #include "base/time.h"
21 #include "base/timer.h"
22 #include "chrome/browser/prerender/prerender_config.h"
23 #include "chrome/browser/prerender/prerender_contents.h"
24 #include "chrome/browser/prerender/prerender_final_status.h"
25 #include "chrome/browser/prerender/prerender_origin.h"
26 #include "chrome/browser/profiles/profile_keyed_service.h"
27 #include "googleurl/src/gurl.h"
29 class Profile;
31 namespace base {
32 class DictionaryValue;
35 namespace content {
36 class WebContents;
39 namespace gfx {
40 class Size;
43 #if defined(COMPILER_GCC)
45 namespace BASE_HASH_NAMESPACE {
46 template <>
47 struct hash<content::WebContents*> {
48 std::size_t operator()(content::WebContents* value) const {
49 return reinterpret_cast<std::size_t>(value);
53 } // namespace BASE_HASH_NAMESPACE
55 #endif
57 namespace prerender {
59 class PrerenderCondition;
60 class PrerenderHandle;
61 class PrerenderHistograms;
62 class PrerenderHistory;
63 class PrerenderLocalPredictor;
64 class PrerenderTracker;
66 // PrerenderManager is responsible for initiating and keeping prerendered
67 // views of web pages. All methods must be called on the UI thread unless
68 // indicated otherwise.
69 class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
70 public base::NonThreadSafe,
71 public ProfileKeyedService {
72 public:
73 // NOTE: New values need to be appended, since they are used in histograms.
74 enum PrerenderManagerMode {
75 PRERENDER_MODE_DISABLED = 0,
76 PRERENDER_MODE_ENABLED = 1,
77 PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP = 2,
78 PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP = 3,
79 // Obsolete: PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP = 4,
80 PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP = 5,
81 PRERENDER_MODE_EXPERIMENT_MULTI_PRERENDER_GROUP = 6,
82 PRERENDER_MODE_EXPERIMENT_15MIN_TTL_GROUP = 7,
83 PRERENDER_MODE_MAX
86 // One or more of these flags must be passed to ClearData() to specify just
87 // what data to clear. See function declaration for more information.
88 enum ClearFlags {
89 CLEAR_PRERENDER_CONTENTS = 0x1 << 0,
90 CLEAR_PRERENDER_HISTORY = 0x1 << 1,
91 CLEAR_MAX = 0x1 << 2
94 // ID indicating that no experiment is active.
95 static const uint8 kNoExperiment = 0;
97 // Owned by a Profile object for the lifetime of the profile.
98 PrerenderManager(Profile* profile, PrerenderTracker* prerender_tracker);
100 virtual ~PrerenderManager();
102 // From ProfileKeyedService:
103 virtual void Shutdown() OVERRIDE;
105 // Entry points for adding prerenders.
107 // Adds a prerender for |url| if valid. |process_id| and |route_id| identify
108 // the RenderView that the prerender request came from. If |size| is empty, a
109 // default from the PrerenderConfig is used. Returns a caller-owned
110 // PrerenderHandle* if the URL was added, NULL if it was not. If the launching
111 // RenderView is itself prerendering, the prerender is added as a pending
112 // prerender.
113 PrerenderHandle* AddPrerenderFromLinkRelPrerender(
114 int process_id,
115 int route_id,
116 const GURL& url,
117 const content::Referrer& referrer,
118 const gfx::Size& size);
120 // Adds a prerender for |url| if valid. As the prerender request is coming
121 // from a source without a RenderViewHost (i.e., the omnibox) we don't have a
122 // child or route id, or a referrer. This method uses sensible values for
123 // those. The |session_storage_namespace| matches the namespace of the active
124 // tab at the time the prerender is generated from the omnibox. Returns a
125 // caller-owned PrerenderHandle*, or NULL.
126 PrerenderHandle* AddPrerenderFromOmnibox(
127 const GURL& url,
128 content::SessionStorageNamespace* session_storage_namespace,
129 const gfx::Size& size);
131 // If |process_id| and |view_id| refer to a running prerender, destroy
132 // it with |final_status|.
133 virtual void DestroyPrerenderForRenderView(int process_id,
134 int view_id,
135 FinalStatus final_status);
137 // Cancels all active prerenders.
138 void CancelAllPrerenders();
140 // If |url| matches a valid prerendered page, try to swap it into
141 // |web_contents| and merge browsing histories. Returns |true| if a
142 // prerendered page is swapped in, |false| otherwise.
143 bool MaybeUsePrerenderedPage(content::WebContents* web_contents,
144 const GURL& url);
146 // Moves a PrerenderContents to the pending delete list from the list of
147 // active prerenders when prerendering should be cancelled.
148 virtual void MoveEntryToPendingDelete(PrerenderContents* entry,
149 FinalStatus final_status);
151 // Records the perceived page load time for a page - effectively the time from
152 // when the user navigates to a page to when it finishes loading. The actual
153 // load may have started prior to navigation due to prerender hints.
154 // This must be called on the UI thread.
155 // |fraction_plt_elapsed_at_swap_in| must either be in [0.0, 1.0], or a value
156 // outside that range indicating that it doesn't apply.
157 static void RecordPerceivedPageLoadTime(
158 base::TimeDelta perceived_page_load_time,
159 double fraction_plt_elapsed_at_swap_in,
160 content::WebContents* web_contents,
161 const GURL& url);
163 // Records the percentage of pixels of the final page in place at swap-in.
164 void RecordFractionPixelsFinalAtSwapin(
165 content::WebContents* web_contents,
166 double fraction);
168 // Set whether prerendering is currently enabled for this manager.
169 // Must be called on the UI thread.
170 // If |enabled| is false, existing prerendered pages will still persist until
171 // they time out, but new ones will not be generated.
172 void set_enabled(bool enabled);
174 // Controls if we launch or squash prefetch requests as they arrive from
175 // renderers.
176 static bool IsPrefetchEnabled();
177 static void SetIsPrefetchEnabled(bool enabled);
179 static PrerenderManagerMode GetMode();
180 static void SetMode(PrerenderManagerMode mode);
181 static const char* GetModeString();
182 static bool IsPrerenderingPossible();
183 static bool ActuallyPrerendering();
184 static bool IsControlGroup(uint8 experiment_id);
185 static bool IsNoUseGroup();
187 // Query the list of current prerender pages to see if the given web contents
188 // is prerendering a page. The optional parameter |origin| is an output
189 // parameter which, if a prerender is found, is set to the Origin of the
190 // prerender |web_contents|.
191 bool IsWebContentsPrerendering(content::WebContents* web_contents,
192 Origin* origin) const;
194 // Returns the PrerenderContents object for the given web_contents if it's
195 // used for an active prerender page, otherwise returns NULL.
196 PrerenderContents* GetPrerenderContents(
197 content::WebContents* web_contents) const;
199 // Returns a list of all WebContents being prerendered.
200 const std::vector<content::WebContents*> GetAllPrerenderingContents() const;
202 // Maintaining and querying the set of WebContents belonging to this
203 // PrerenderManager that are currently showing prerendered pages.
204 void MarkWebContentsAsPrerendered(content::WebContents* web_contents,
205 Origin origin);
206 void MarkWebContentsAsWouldBePrerendered(content::WebContents* web_contents,
207 Origin origin);
208 void MarkWebContentsAsNotPrerendered(content::WebContents* web_contents);
210 // Returns true if |web_contents| was originally a prerender that has since
211 // been swapped in. The optional parameter |origin| is an output parameter
212 // which, if a prerender is found, is set to the Origin of the prerender of
213 // |web_contents|.
214 bool IsWebContentsPrerendered(content::WebContents* web_contents,
215 Origin* origin) const;
216 bool WouldWebContentsBePrerendered(content::WebContents* web_contents,
217 Origin* origin) const;
219 // Checks whether |url| has been recently navigated to.
220 bool HasRecentlyBeenNavigatedTo(Origin origin, const GURL& url);
222 // Returns true iff the method given is valid for prerendering.
223 static bool IsValidHttpMethod(const std::string& method);
225 // Returns true iff the scheme of the URL given is valid for prerendering.
226 static bool DoesURLHaveValidScheme(const GURL& url);
228 // Returns a Value object containing the active pages being prerendered, and
229 // a history of pages which were prerendered. The caller is responsible for
230 // deleting the return value.
231 base::DictionaryValue* GetAsValue() const;
233 // Clears the data indicated by which bits of clear_flags are set.
235 // If the CLEAR_PRERENDER_CONTENTS bit is set, all active prerenders are
236 // cancelled and then deleted, and any WebContents queued for destruction are
237 // destroyed as well.
239 // If the CLEAR_PRERENDER_HISTORY bit is set, the prerender history is
240 // cleared, including any entries newly created by destroying them in
241 // response to the CLEAR_PRERENDER_CONTENTS flag.
243 // Intended to be used when clearing the cache or history.
244 void ClearData(int clear_flags);
246 // Record a final status of a prerendered page in a histogram.
247 // This variation allows specifying whether prerendering had been started
248 // (necessary to flag MatchComplete dummies).
249 void RecordFinalStatusWithMatchCompleteStatus(
250 Origin origin,
251 uint8 experiment_id,
252 PrerenderContents::MatchCompleteStatus mc_status,
253 FinalStatus final_status) const;
255 const Config& config() const { return config_; }
256 Config& mutable_config() { return config_; }
258 PrerenderTracker* prerender_tracker() { return prerender_tracker_; }
260 // Adds a condition. This is owned by the PrerenderManager.
261 void AddCondition(const PrerenderCondition* condition);
263 // Records that some visible tab navigated (or was redirected) to the
264 // provided URL.
265 void RecordNavigation(const GURL& url);
267 Profile* profile() const { return profile_; }
269 // Classes which will be tested in prerender unit browser tests should use
270 // these methods to get times for comparison, so that the test framework can
271 // mock advancing/retarding time.
272 virtual base::Time GetCurrentTime() const;
273 virtual base::TimeTicks GetCurrentTimeTicks() const;
275 protected:
276 class PrerenderData : public base::SupportsWeakPtr<PrerenderData> {
277 public:
278 struct OrderByExpiryTime;
280 PrerenderData(PrerenderManager* manager,
281 PrerenderContents* contents,
282 base::TimeTicks expiry_time);
284 ~PrerenderData();
286 // Turn this PrerenderData into a Match Complete replacement for itself,
287 // placing the current prerender contents into |to_delete_prerenders_|.
288 void MakeIntoMatchCompleteReplacement();
290 // A new PrerenderHandle has been created for this PrerenderData.
291 void OnHandleCreated(PrerenderHandle* prerender_handle);
293 // The launcher associated with a handle is navigating away from the context
294 // that launched this prerender. If the prerender is active, it may stay
295 // alive briefly though, in case we we going through a redirect chain that
296 // will eventually land at it.
297 void OnHandleNavigatedAway(PrerenderHandle* prerender_handle);
299 // The launcher associated with a handle has taken explicit action to cancel
300 // this prerender. We may well destroy the prerender in this case if no
301 // other handles continue to track it.
302 void OnHandleCanceled(PrerenderHandle* prerender_handle);
304 PrerenderContents* contents() { return contents_.get(); }
306 PrerenderContents* ReleaseContents();
308 int handle_count() const { return handle_count_; }
310 base::TimeTicks expiry_time() const { return expiry_time_; }
311 void set_expiry_time(base::TimeTicks expiry_time) {
312 expiry_time_ = expiry_time;
315 private:
316 PrerenderManager* manager_;
317 scoped_ptr<PrerenderContents> contents_;
319 // The number of distinct PrerenderHandles created for |this|, including
320 // ones that have called PrerenderData::OnHandleNavigatedAway(), but not
321 // counting the ones that have called PrerenderData::OnHandleCanceled(). For
322 // pending prerenders, this will always be 1, since the PrerenderManager
323 // only merges handles of running prerenders.
324 int handle_count_;
326 // After this time, this prerender is no longer fresh, and should be
327 // removed.
328 base::TimeTicks expiry_time_;
330 DISALLOW_COPY_AND_ASSIGN(PrerenderData);
333 void SetPrerenderContentsFactory(
334 PrerenderContents::Factory* prerender_contents_factory);
336 // Adds prerenders from the pending Prerenders, called by
337 // PrerenderContents::StartPendingPrerenders.
338 void StartPendingPrerenders(
339 int process_id,
340 ScopedVector<PrerenderContents::PendingPrerenderInfo>* pending_prerenders,
341 content::SessionStorageNamespace* session_storage_namespace);
343 // Called by a PrerenderData to signal that the launcher has navigated away
344 // from the context that launched the prerender. A user may have clicked
345 // a link in a page containing a <link rel=prerender> element, or the user
346 // might have committed an omnibox navigation. This is used to possibly
347 // shorten the TTL of the prerendered page.
348 void SourceNavigatedAway(PrerenderData* prerender_data);
350 private:
351 friend class PrerenderBrowserTest;
352 friend class PrerenderContents;
353 friend class PrerenderHandle;
354 friend class UnitTestPrerenderManager;
356 class OnCloseWebContentsDeleter;
357 struct NavigationRecord;
359 // For each WebContents that is swapped in, we store a
360 // PrerenderedWebContentsData so that we can track the origin of the
361 // prerender.
362 struct PrerenderedWebContentsData {
363 explicit PrerenderedWebContentsData(Origin origin);
365 Origin origin;
368 // In the control group experimental group for each WebContents "not swapped
369 // in" we create a WouldBePrerenderedWebContentsData to the origin of the
370 // "prerender" we did not launch. We also track a state machine to ensure
371 // the histogram reporting tracks what histograms would have done.
372 struct WouldBePrerenderedWebContentsData {
373 // When the WebContents gets a provisional load, we'd like to remove the
374 // WebContents from the map since the new navigation would not have swapped
375 // in a prerender. But the first provisional load after the control
376 // prerender is not "swapped in" is actually to the prerendered location! So
377 // we don't remove the item from the map on the first provisional load, but
378 // we do for subsequent loads.
379 enum State {
380 WAITING_FOR_PROVISIONAL_LOAD,
381 SEEN_PROVISIONAL_LOAD,
384 explicit WouldBePrerenderedWebContentsData(Origin origin);
386 Origin origin;
387 State state;
390 // Time interval before a new prerender is allowed.
391 static const int kMinTimeBetweenPrerendersMs = 500;
393 // Time window for which we record old navigations, in milliseconds.
394 static const int kNavigationRecordWindowMs = 5000;
396 void OnCancelPrerenderHandle(PrerenderData* prerender_data);
398 // Adds a prerender for |url| from |referrer| initiated from the process
399 // |child_id|. The |origin| specifies how the prerender was added. If |size|
400 // is empty, then PrerenderContents::StartPrerendering will instead use a
401 // default from PrerenderConfig. Returns a PrerenderHandle*, owned by the
402 // caller, or NULL.
403 PrerenderHandle* AddPrerender(
404 Origin origin,
405 int child_id,
406 const GURL& url,
407 const content::Referrer& referrer,
408 const gfx::Size& size,
409 content::SessionStorageNamespace* session_storage_namespace);
411 void StartSchedulingPeriodicCleanups();
412 void StopSchedulingPeriodicCleanups();
414 void EvictOldestPrerendersIfNecessary();
416 // Deletes stale and cancelled prerendered PrerenderContents, as well as
417 // WebContents that have been replaced by prerendered WebContents.
418 // Also identifies and kills PrerenderContents that use too much
419 // resources.
420 void PeriodicCleanup();
422 // Posts a task to call PeriodicCleanup. Results in quicker destruction of
423 // objects. If |this| is deleted before the task is run, the task will
424 // automatically be cancelled.
425 void PostCleanupTask();
427 base::TimeTicks GetExpiryTimeForNewPrerender() const;
428 base::TimeTicks GetExpiryTimeForNavigatedAwayPrerender() const;
430 void DeleteOldEntries();
431 virtual PrerenderContents* CreatePrerenderContents(
432 const GURL& url,
433 const content::Referrer& referrer,
434 Origin origin,
435 uint8 experiment_id);
437 // Insures the |active_prerenders_| are sorted by increasing expiry time. Call
438 // after every mutation of active_prerenders_ that can possibly make it
439 // unsorted (e.g. an insert, or changing an expiry time).
440 void SortActivePrerenders();
442 // Finds the active PrerenderData object for a running prerender matching
443 // |url| and |session_storage_namespace|.
444 PrerenderData* FindPrerenderData(
445 const GURL& url,
446 const content::SessionStorageNamespace* session_storage_namespace);
448 // If |child_id| and |route_id| correspond to a RenderView that is an active
449 // prerender, returns the PrerenderData object for that prerender. Otherwise,
450 // returns NULL.
451 PrerenderData* FindPrerenderDataForChildAndRoute(int child_id, int route_id);
453 // Given the |prerender_contents|, find the iterator in active_prerenders_
454 // correponding to the given prerender.
455 ScopedVector<PrerenderData>::iterator
456 FindIteratorForPrerenderContents(PrerenderContents* prerender_contents);
458 bool DoesRateLimitAllowPrerender(Origin origin) const;
460 // Deletes old WebContents that have been replaced by prerendered ones. This
461 // is needed because they're replaced in a callback from the old WebContents,
462 // so cannot immediately be deleted.
463 void DeleteOldWebContents();
465 // Cleans up old NavigationRecord's.
466 void CleanUpOldNavigations();
468 // Arrange for the given WebContents to be deleted asap. If deleter is not
469 // NULL, deletes that as well.
470 void ScheduleDeleteOldWebContents(content::WebContents* tab,
471 OnCloseWebContentsDeleter* deleter);
473 // Adds to the history list.
474 void AddToHistory(PrerenderContents* contents);
476 // Returns a new Value representing the pages currently being prerendered. The
477 // caller is responsible for delete'ing the return value.
478 base::Value* GetActivePrerendersAsValue() const;
480 // Destroys all pending prerenders using FinalStatus. Also deletes them as
481 // well as any swapped out WebContents queued for destruction.
482 // Used both on destruction, and when clearing the browsing history.
483 void DestroyAllContents(FinalStatus final_status);
485 // Helper function to destroy a PrerenderContents with the specified
486 // final_status, while at the same time recording that for the MatchComplete
487 // case, that this prerender would have been used.
488 void DestroyAndMarkMatchCompleteAsUsed(PrerenderContents* prerender_contents,
489 FinalStatus final_status);
491 // Record a final status of a prerendered page in a histogram.
492 // This is a helper function which will ultimately call
493 // RecordFinalStatusWthMatchCompleteStatus, using MATCH_COMPLETE_DEFAULT.
494 void RecordFinalStatus(Origin origin,
495 uint8 experiment_id,
496 FinalStatus final_status) const;
498 // Returns whether prerendering is currently enabled for this manager.
499 // Must be called on the UI thread.
500 bool IsEnabled() const;
502 // The configuration.
503 Config config_;
505 // Specifies whether prerendering is currently enabled for this
506 // manager. The value can change dynamically during the lifetime
507 // of the PrerenderManager.
508 bool enabled_;
510 static bool is_prefetch_enabled_;
512 // The profile that owns this PrerenderManager.
513 Profile* profile_;
515 PrerenderTracker* prerender_tracker_;
517 // All running prerenders. Sorted by expiry time, in ascending order.
518 ScopedVector<PrerenderData> active_prerenders_;
520 // Prerenders awaiting deletion.
521 ScopedVector<PrerenderData> to_delete_prerenders_;
523 // List of recent navigations in this profile, sorted by ascending
524 // navigate_time_.
525 std::list<NavigationRecord> navigations_;
527 // This map is from all WebContents which are currently displaying a
528 // prerendered page which has already been swapped in to a
529 // PrerenderedWebContentsData for tracking full lifetime information
530 // on prerenders.
531 base::hash_map<content::WebContents*, PrerenderedWebContentsData>
532 prerendered_web_contents_data_;
534 // WebContents that would have been swapped out for a prerendered WebContents
535 // if the user was not part of the control group for measurement. When the
536 // WebContents gets a provisional load, the WebContents is removed from
537 // the map since the new navigation would not have swapped in a prerender.
538 // However, one complication exists because the first provisional load after
539 // the WebContents is marked as "Would Have Been Prerendered" is actually to
540 // the prerendered location. So, we need to keep a state around that does
541 // not clear the item from the map on the first provisional load, but does
542 // for subsequent loads.
543 base::hash_map<content::WebContents*, WouldBePrerenderedWebContentsData>
544 would_be_prerendered_map_;
546 scoped_ptr<PrerenderContents::Factory> prerender_contents_factory_;
548 static PrerenderManagerMode mode_;
550 // A count of how many prerenders we do per session. Initialized to 0 then
551 // incremented and emitted to a histogram on each successful prerender.
552 static int prerenders_per_session_count_;
554 // RepeatingTimer to perform periodic cleanups of pending prerendered
555 // pages.
556 base::RepeatingTimer<PrerenderManager> repeating_timer_;
558 // Track time of last prerender to limit prerender spam.
559 base::TimeTicks last_prerender_start_time_;
561 std::list<content::WebContents*> old_web_contents_list_;
563 // Cancels pending tasks on deletion.
564 base::WeakPtrFactory<PrerenderManager> weak_factory_;
566 ScopedVector<OnCloseWebContentsDeleter> on_close_web_contents_deleters_;
568 scoped_ptr<PrerenderHistory> prerender_history_;
570 std::list<const PrerenderCondition*> prerender_conditions_;
572 scoped_ptr<PrerenderHistograms> histograms_;
574 scoped_ptr<PrerenderLocalPredictor> local_predictor_;
576 DISALLOW_COPY_AND_ASSIGN(PrerenderManager);
579 PrerenderManager* FindPrerenderManagerUsingRenderProcessId(
580 int render_process_id);
582 } // namespace prerender
584 #endif // CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_