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_
12 #include "base/gtest_prod_util.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/scoped_vector.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/task/cancelable_task_tracker.h"
17 #include "base/threading/non_thread_safe.h"
18 #include "base/time/time.h"
19 #include "base/timer/timer.h"
20 #include "chrome/browser/history/history_service.h"
21 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
22 #include "chrome/browser/predictors/logged_in_predictor_table.h"
23 #include "chrome/browser/prerender/prerender_config.h"
24 #include "chrome/browser/prerender/prerender_contents.h"
25 #include "chrome/browser/prerender/prerender_final_status.h"
26 #include "chrome/browser/prerender/prerender_histograms.h"
27 #include "chrome/browser/prerender/prerender_origin.h"
28 #include "components/keyed_service/core/keyed_service.h"
29 #include "content/public/browser/notification_observer.h"
30 #include "content/public/browser/notification_registrar.h"
31 #include "content/public/browser/render_process_host_observer.h"
32 #include "net/cookies/canonical_cookie.h"
33 #include "net/cookies/cookie_monster.h"
37 class InstantSearchPrerendererTest
;
38 struct ChromeCookieDetails
;
41 class DictionaryValue
;
45 struct NavigateParams
;
58 class PrerenderHandle
;
59 class PrerenderHistory
;
60 class PrerenderLocalPredictor
;
62 // PrerenderManager is responsible for initiating and keeping prerendered
63 // views of web pages. All methods must be called on the UI thread unless
64 // indicated otherwise.
65 class PrerenderManager
: public base::SupportsWeakPtr
<PrerenderManager
>,
66 public base::NonThreadSafe
,
67 public content::NotificationObserver
,
68 public content::RenderProcessHostObserver
,
70 public MediaCaptureDevicesDispatcher::Observer
{
72 // NOTE: New values need to be appended, since they are used in histograms.
73 enum PrerenderManagerMode
{
74 PRERENDER_MODE_DISABLED
= 0,
75 PRERENDER_MODE_ENABLED
= 1,
76 PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP
= 2,
77 PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP
= 3,
78 // Obsolete: PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP = 4,
79 PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP
= 5,
80 PRERENDER_MODE_EXPERIMENT_MULTI_PRERENDER_GROUP
= 6,
81 PRERENDER_MODE_EXPERIMENT_15MIN_TTL_GROUP
= 7,
82 PRERENDER_MODE_EXPERIMENT_MATCH_COMPLETE_GROUP
= 8,
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.
89 CLEAR_PRERENDER_CONTENTS
= 0x1 << 0,
90 CLEAR_PRERENDER_HISTORY
= 0x1 << 1,
94 typedef predictors::LoggedInPredictorTable::LoggedInStateMap LoggedInStateMap
;
96 // ID indicating that no experiment is active.
97 static const uint8 kNoExperiment
= 0;
99 // Owned by a Profile object for the lifetime of the profile.
100 explicit PrerenderManager(Profile
* profile
);
102 ~PrerenderManager() override
;
104 // From KeyedService:
105 void Shutdown() override
;
107 // Entry points for adding prerenders.
109 // Adds a prerender for |url| if valid. |process_id| and |route_id| identify
110 // the RenderView that the prerender request came from. If |size| is empty, a
111 // default from the PrerenderConfig is used. Returns a caller-owned
112 // PrerenderHandle* if the URL was added, NULL if it was not. If the launching
113 // RenderView is itself prerendering, the prerender is added as a pending
115 PrerenderHandle
* AddPrerenderFromLinkRelPrerender(
120 const content::Referrer
& referrer
,
121 const gfx::Size
& size
);
123 // Adds a prerender for |url| if valid. As the prerender request is coming
124 // from a source without a RenderFrameHost (i.e., the omnibox) we don't have a
125 // child or route id, or a referrer. This method uses sensible values for
126 // those. The |session_storage_namespace| matches the namespace of the active
127 // tab at the time the prerender is generated from the omnibox. Returns a
128 // caller-owned PrerenderHandle*, or NULL.
129 PrerenderHandle
* AddPrerenderFromOmnibox(
131 content::SessionStorageNamespace
* session_storage_namespace
,
132 const gfx::Size
& size
);
134 PrerenderHandle
* AddPrerenderFromLocalPredictor(
136 content::SessionStorageNamespace
* session_storage_namespace
,
137 const gfx::Size
& size
);
139 PrerenderHandle
* AddPrerenderFromExternalRequest(
141 const content::Referrer
& referrer
,
142 content::SessionStorageNamespace
* session_storage_namespace
,
143 const gfx::Size
& size
);
145 // Adds a prerender for Instant Search |url| if valid. The
146 // |session_storage_namespace| matches the namespace of the active tab at the
147 // time the prerender is generated. Returns a caller-owned PrerenderHandle* or
149 PrerenderHandle
* AddPrerenderForInstant(
151 content::SessionStorageNamespace
* session_storage_namespace
,
152 const gfx::Size
& size
);
154 // Cancels all active prerenders.
155 void CancelAllPrerenders();
157 // If |url| matches a valid prerendered page and |params| are compatible, try
158 // to swap it and merge browsing histories. Returns |true| and updates
159 // |params->target_contents| if a prerendered page is swapped in, |false|
161 bool MaybeUsePrerenderedPage(const GURL
& url
,
162 chrome::NavigateParams
* params
);
164 // Moves a PrerenderContents to the pending delete list from the list of
165 // active prerenders when prerendering should be cancelled.
166 virtual void MoveEntryToPendingDelete(PrerenderContents
* entry
,
167 FinalStatus final_status
);
169 // Records the page load time for a prerender that wasn't swapped in.
170 void RecordPageLoadTimeNotSwappedIn(Origin origin
,
171 base::TimeDelta page_load_time
,
174 // Records the perceived page load time for a page - effectively the time from
175 // when the user navigates to a page to when it finishes loading. The actual
176 // load may have started prior to navigation due to prerender hints.
177 // This must be called on the UI thread.
178 // |fraction_plt_elapsed_at_swap_in| must either be in [0.0, 1.0], or a value
179 // outside that range indicating that it doesn't apply.
180 void RecordPerceivedPageLoadTime(
182 NavigationType navigation_type
,
183 base::TimeDelta perceived_page_load_time
,
184 double fraction_plt_elapsed_at_swap_in
,
187 static PrerenderManagerMode
GetMode();
188 static void SetMode(PrerenderManagerMode mode
);
189 static const char* GetModeString();
190 static bool IsPrerenderingPossible();
191 static bool ActuallyPrerendering();
192 static bool IsControlGroup(uint8 experiment_id
);
193 static bool IsNoUseGroup();
195 // Query the list of current prerender pages to see if the given web contents
196 // is prerendering a page. The optional parameter |origin| is an output
197 // parameter which, if a prerender is found, is set to the Origin of the
198 // prerender |web_contents|.
199 bool IsWebContentsPrerendering(const content::WebContents
* web_contents
,
200 Origin
* origin
) const;
202 // Whether the PrerenderManager has an active prerender with the given url and
203 // SessionStorageNamespace associated with the given WebContens.
204 bool HasPrerenderedUrl(GURL url
, content::WebContents
* web_contents
) const;
206 // Returns the PrerenderContents object for the given web_contents, otherwise
207 // returns NULL. Note that the PrerenderContents may have been Destroy()ed,
208 // but not yet deleted.
209 PrerenderContents
* GetPrerenderContents(
210 const content::WebContents
* web_contents
) const;
212 // Returns the PrerenderContents object for a given child_id, route_id pair,
213 // otherwise returns NULL. Note that the PrerenderContents may have been
214 // Destroy()ed, but not yet deleted.
215 virtual PrerenderContents
* GetPrerenderContentsForRoute(
216 int child_id
, int route_id
) const;
218 // Returns a list of all WebContents being prerendered.
219 const std::vector
<content::WebContents
*> GetAllPrerenderingContents() const;
221 // Checks whether |url| has been recently navigated to.
222 bool HasRecentlyBeenNavigatedTo(Origin origin
, const GURL
& url
);
224 // Returns true iff the method given is valid for prerendering.
225 static bool IsValidHttpMethod(const std::string
& method
);
227 // Returns true iff the scheme of the URL given is valid for prerendering.
228 static bool DoesURLHaveValidScheme(const GURL
& url
);
230 // Returns true iff the scheme of the subresource URL given is valid for
232 static bool DoesSubresourceURLHaveValidScheme(const GURL
& url
);
234 // Returns a Value object containing the active pages being prerendered, and
235 // a history of pages which were prerendered. The caller is responsible for
236 // deleting the return value.
237 base::DictionaryValue
* GetAsValue() const;
239 // Clears the data indicated by which bits of clear_flags are set.
241 // If the CLEAR_PRERENDER_CONTENTS bit is set, all active prerenders are
242 // cancelled and then deleted, and any WebContents queued for destruction are
243 // destroyed as well.
245 // If the CLEAR_PRERENDER_HISTORY bit is set, the prerender history is
246 // cleared, including any entries newly created by destroying them in
247 // response to the CLEAR_PRERENDER_CONTENTS flag.
249 // Intended to be used when clearing the cache or history.
250 void ClearData(int clear_flags
);
252 // Record a final status of a prerendered page in a histogram.
253 // This variation allows specifying whether prerendering had been started
254 // (necessary to flag MatchComplete dummies).
255 void RecordFinalStatusWithMatchCompleteStatus(
258 PrerenderContents::MatchCompleteStatus mc_status
,
259 FinalStatus final_status
) const;
261 // Record a cookie status histogram (see prerender_histograms.h).
262 void RecordCookieStatus(Origin origin
,
264 int cookie_status
) const;
266 // Record a cookie send type histogram (see prerender_histograms.h).
267 void RecordCookieSendType(Origin origin
,
269 int cookie_send_type
) const;
271 // content::NotificationObserver
272 void Observe(int type
,
273 const content::NotificationSource
& source
,
274 const content::NotificationDetails
& details
) override
;
276 // MediaCaptureDevicesDispatcher::Observer
277 void OnCreatingAudioStream(int render_process_id
,
278 int render_frame_id
) override
;
280 const Config
& config() const { return config_
; }
281 Config
& mutable_config() { return config_
; }
283 // Records that some visible tab navigated (or was redirected) to the
285 void RecordNavigation(const GURL
& url
);
287 // Updates the LoggedInPredictor state to reflect that a login has likely
288 // on the URL provided.
289 void RecordLikelyLoginOnURL(const GURL
& url
);
291 // Checks if the LoggedInPredictor shows that the user is likely logged on
292 // to the site for the URL provided.
293 void CheckIfLikelyLoggedInOnURL(const GURL
& url
,
295 bool* database_was_present
,
296 const base::Closure
& result_cb
);
298 void OnHistoryServiceDidQueryURL(Origin origin
,
301 const history::URLRow
& url_row
,
302 const history::VisitVector
& visits
);
304 Profile
* profile() const { return profile_
; }
306 // Classes which will be tested in prerender unit browser tests should use
307 // these methods to get times for comparison, so that the test framework can
308 // mock advancing/retarding time.
309 virtual base::Time
GetCurrentTime() const;
310 virtual base::TimeTicks
GetCurrentTimeTicks() const;
312 scoped_refptr
<predictors::LoggedInPredictorTable
>
313 logged_in_predictor_table() {
314 return logged_in_predictor_table_
;
317 PrerenderLocalPredictor
* local_predictor() {
318 return local_predictor_
.get();
321 // Notification that a cookie event happened on a render frame. Will record a
322 // cookie event for a given render frame, if it is being prerendered.
323 // If cookies were sent, all cookies must be supplied in |cookie_list|.
324 static void RecordCookieEvent(int process_id
,
327 const GURL
& frame_url
,
328 bool is_for_blocking_resource
,
329 PrerenderContents::CookieEvent event
,
330 const net::CookieList
* cookie_list
);
332 // Notification that a prerender has completed and its bytes should be
334 void RecordNetworkBytes(Origin origin
, bool used
, int64 prerender_bytes
);
336 // Returns whether prerendering is currently enabled for this manager.
337 bool IsEnabled() const;
339 // Add to the running tally of bytes transferred over the network for this
340 // profile if prerendering is currently enabled.
341 void AddProfileNetworkBytesIfEnabled(int64 bytes
);
343 // Registers a new ProcessHost performing a prerender. Called by
344 // PrerenderContents.
345 void AddPrerenderProcessHost(content::RenderProcessHost
* process_host
);
347 // Returns whether or not |process_host| may be reused for new navigations
348 // from a prerendering perspective. Currently, if Prerender Cookie Stores are
349 // enabled, prerenders must be in their own processes that may not be shared.
350 bool MayReuseProcessHost(content::RenderProcessHost
* process_host
);
352 // content::RenderProcessHostObserver implementation.
353 void RenderProcessHostDestroyed(content::RenderProcessHost
* host
) override
;
356 class PrerenderData
: public base::SupportsWeakPtr
<PrerenderData
> {
358 struct OrderByExpiryTime
;
360 PrerenderData(PrerenderManager
* manager
,
361 PrerenderContents
* contents
,
362 base::TimeTicks expiry_time
);
366 // Turn this PrerenderData into a Match Complete replacement for itself,
367 // placing the current prerender contents into |to_delete_prerenders_|.
368 void MakeIntoMatchCompleteReplacement();
370 // A new PrerenderHandle has been created for this PrerenderData.
371 void OnHandleCreated(PrerenderHandle
* prerender_handle
);
373 // The launcher associated with a handle is navigating away from the context
374 // that launched this prerender. If the prerender is active, it may stay
375 // alive briefly though, in case we we going through a redirect chain that
376 // will eventually land at it.
377 void OnHandleNavigatedAway(PrerenderHandle
* prerender_handle
);
379 // The launcher associated with a handle has taken explicit action to cancel
380 // this prerender. We may well destroy the prerender in this case if no
381 // other handles continue to track it.
382 void OnHandleCanceled(PrerenderHandle
* prerender_handle
);
384 PrerenderContents
* contents() { return contents_
.get(); }
386 PrerenderContents
* ReleaseContents();
388 int handle_count() const { return handle_count_
; }
390 base::TimeTicks
abandon_time() const { return abandon_time_
; }
392 base::TimeTicks
expiry_time() const { return expiry_time_
; }
393 void set_expiry_time(base::TimeTicks expiry_time
) {
394 expiry_time_
= expiry_time
;
398 PrerenderManager
* manager_
;
399 scoped_ptr
<PrerenderContents
> contents_
;
401 // The number of distinct PrerenderHandles created for |this|, including
402 // ones that have called PrerenderData::OnHandleNavigatedAway(), but not
403 // counting the ones that have called PrerenderData::OnHandleCanceled(). For
404 // pending prerenders, this will always be 1, since the PrerenderManager
405 // only merges handles of running prerenders.
408 // The time when OnHandleNavigatedAway was called.
409 base::TimeTicks abandon_time_
;
411 // After this time, this prerender is no longer fresh, and should be
413 base::TimeTicks expiry_time_
;
415 DISALLOW_COPY_AND_ASSIGN(PrerenderData
);
418 void SetPrerenderContentsFactory(
419 PrerenderContents::Factory
* prerender_contents_factory
);
421 // Called by a PrerenderData to signal that the launcher has navigated away
422 // from the context that launched the prerender. A user may have clicked
423 // a link in a page containing a <link rel=prerender> element, or the user
424 // might have committed an omnibox navigation. This is used to possibly
425 // shorten the TTL of the prerendered page.
426 void SourceNavigatedAway(PrerenderData
* prerender_data
);
429 friend class ::InstantSearchPrerendererTest
;
430 friend class PrerenderBrowserTest
;
431 friend class PrerenderContents
;
432 friend class PrerenderHandle
;
433 friend class UnitTestPrerenderManager
;
435 class OnCloseWebContentsDeleter
;
436 struct NavigationRecord
;
438 // Time interval before a new prerender is allowed.
439 static const int kMinTimeBetweenPrerendersMs
= 500;
441 // Time window for which we record old navigations, in milliseconds.
442 static const int kNavigationRecordWindowMs
= 5000;
444 void OnCancelPrerenderHandle(PrerenderData
* prerender_data
);
446 // Adds a prerender for |url| from |referrer|. The |origin| specifies how the
447 // prerender was added. If |size| is empty, then
448 // PrerenderContents::StartPrerendering will instead use a default from
449 // PrerenderConfig. Returns a PrerenderHandle*, owned by the caller, or NULL.
450 PrerenderHandle
* AddPrerender(
453 const content::Referrer
& referrer
,
454 const gfx::Size
& size
,
455 content::SessionStorageNamespace
* session_storage_namespace
);
457 void StartSchedulingPeriodicCleanups();
458 void StopSchedulingPeriodicCleanups();
460 void EvictOldestPrerendersIfNecessary();
462 // Deletes stale and cancelled prerendered PrerenderContents, as well as
463 // WebContents that have been replaced by prerendered WebContents.
464 // Also identifies and kills PrerenderContents that use too much
466 void PeriodicCleanup();
468 // Posts a task to call PeriodicCleanup. Results in quicker destruction of
469 // objects. If |this| is deleted before the task is run, the task will
470 // automatically be cancelled.
471 void PostCleanupTask();
473 base::TimeTicks
GetExpiryTimeForNewPrerender(Origin origin
) const;
474 base::TimeTicks
GetExpiryTimeForNavigatedAwayPrerender() const;
476 void DeleteOldEntries();
477 virtual PrerenderContents
* CreatePrerenderContents(
479 const content::Referrer
& referrer
,
481 uint8 experiment_id
);
483 // Insures the |active_prerenders_| are sorted by increasing expiry time. Call
484 // after every mutation of active_prerenders_ that can possibly make it
485 // unsorted (e.g. an insert, or changing an expiry time).
486 void SortActivePrerenders();
488 // Finds the active PrerenderData object for a running prerender matching
489 // |url| and |session_storage_namespace|.
490 PrerenderData
* FindPrerenderData(
492 const content::SessionStorageNamespace
* session_storage_namespace
);
494 // Given the |prerender_contents|, find the iterator in active_prerenders_
495 // correponding to the given prerender.
496 ScopedVector
<PrerenderData
>::iterator
497 FindIteratorForPrerenderContents(PrerenderContents
* prerender_contents
);
499 bool DoesRateLimitAllowPrerender(Origin origin
) const;
501 // Deletes old WebContents that have been replaced by prerendered ones. This
502 // is needed because they're replaced in a callback from the old WebContents,
503 // so cannot immediately be deleted.
504 void DeleteOldWebContents();
506 // Cleans up old NavigationRecord's.
507 void CleanUpOldNavigations();
509 // Arrange for the given WebContents to be deleted asap. If deleter is not
510 // NULL, deletes that as well.
511 void ScheduleDeleteOldWebContents(content::WebContents
* tab
,
512 OnCloseWebContentsDeleter
* deleter
);
514 // Adds to the history list.
515 void AddToHistory(PrerenderContents
* contents
);
517 // Returns a new Value representing the pages currently being prerendered. The
518 // caller is responsible for delete'ing the return value.
519 base::Value
* GetActivePrerendersAsValue() const;
521 // Destroys all pending prerenders using FinalStatus. Also deletes them as
522 // well as any swapped out WebContents queued for destruction.
523 // Used both on destruction, and when clearing the browsing history.
524 void DestroyAllContents(FinalStatus final_status
);
526 // Helper function to destroy a PrerenderContents with the specified
527 // final_status, while at the same time recording that for the MatchComplete
528 // case, that this prerender would have been used.
529 void DestroyAndMarkMatchCompleteAsUsed(PrerenderContents
* prerender_contents
,
530 FinalStatus final_status
);
532 // Records the final status a prerender in the case that a PrerenderContents
533 // was never created, and also adds a PrerenderHistory entry.
534 // This is a helper function which will ultimately call
535 // RecordFinalStatusWthMatchCompleteStatus, using MATCH_COMPLETE_DEFAULT.
536 void RecordFinalStatusWithoutCreatingPrerenderContents(
537 const GURL
& url
, Origin origin
, uint8 experiment_id
,
538 FinalStatus final_status
) const;
541 void CookieChanged(ChromeCookieDetails
* details
);
542 void CookieChangedAnyCookiesLeftLookupResult(const std::string
& domain_key
,
544 void LoggedInPredictorDataReceived(scoped_ptr
<LoggedInStateMap
> new_map
);
546 // Swaps a prerender |prerender_data| for |url| into the tab, replacing
547 // |web_contents|. Returns the new WebContents that was swapped in, or NULL
548 // if a swap-in was not possible. If |should_replace_current_entry| is true,
549 // the current history entry in |web_contents| is replaced.
550 content::WebContents
* SwapInternal(const GURL
& url
,
551 content::WebContents
* web_contents
,
552 PrerenderData
* prerender_data
,
553 bool should_replace_current_entry
);
555 // The configuration.
558 // The profile that owns this PrerenderManager.
561 // All running prerenders. Sorted by expiry time, in ascending order.
562 ScopedVector
<PrerenderData
> active_prerenders_
;
564 // Prerenders awaiting deletion.
565 ScopedVector
<PrerenderData
> to_delete_prerenders_
;
567 // List of recent navigations in this profile, sorted by ascending
569 std::list
<NavigationRecord
> navigations_
;
571 scoped_ptr
<PrerenderContents::Factory
> prerender_contents_factory_
;
573 static PrerenderManagerMode mode_
;
575 // A count of how many prerenders we do per session. Initialized to 0 then
576 // incremented and emitted to a histogram on each successful prerender.
577 static int prerenders_per_session_count_
;
579 // RepeatingTimer to perform periodic cleanups of pending prerendered
581 base::RepeatingTimer
<PrerenderManager
> repeating_timer_
;
583 // Track time of last prerender to limit prerender spam.
584 base::TimeTicks last_prerender_start_time_
;
586 std::list
<content::WebContents
*> old_web_contents_list_
;
588 ScopedVector
<OnCloseWebContentsDeleter
> on_close_web_contents_deleters_
;
590 scoped_ptr
<PrerenderHistory
> prerender_history_
;
592 scoped_ptr
<PrerenderHistograms
> histograms_
;
594 scoped_ptr
<PrerenderLocalPredictor
> local_predictor_
;
596 scoped_refptr
<predictors::LoggedInPredictorTable
> logged_in_predictor_table_
;
598 // Here, we keep the logged in predictor state, but potentially a superset
599 // of its actual (database-backed) state, since we do not incorporate
600 // browser data deletion. We do not use this for actual lookups, but only
601 // to query cookie data for domains we know there was a login before.
602 // This is required to avoid a large number of cookie lookups on bulk
603 // deletion of cookies.
604 scoped_ptr
<LoggedInStateMap
> logged_in_state_
;
606 content::NotificationRegistrar notification_registrar_
;
608 base::CancelableTaskTracker query_url_tracker_
;
610 // The number of bytes transferred over the network for the profile this
611 // PrerenderManager is attached to.
612 int64 profile_network_bytes_
;
614 // The value of profile_network_bytes_ that was last recorded.
615 int64 last_recorded_profile_network_bytes_
;
617 // Set of process hosts being prerendered.
618 typedef std::set
<content::RenderProcessHost
*> PrerenderProcessSet
;
619 PrerenderProcessSet prerender_process_hosts_
;
621 DISALLOW_COPY_AND_ASSIGN(PrerenderManager
);
624 } // namespace prerender
626 #endif // CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_