blob: 8917abcfefac5e147ccacca90dc492d4f718bf5d [file] [log] [blame]
// 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/task.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);
// 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.
virtual 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);
// Moves a PrerenderContents to the pending delete list from the list of
// active prerenders when prerendering should be cancelled.
void MoveEntryToPendingDelete(PrerenderContents* entry);
// Checks if the PrerenderContents has been added to the pending delete list.
bool IsPendingDelete(PrerenderContents* entry) const;
// 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();
// Query the list of current prerender pages to see if the given tab contents
// is prerendering a page.
bool IsTabContentsPrerendering(TabContents* tab_contents) const;
// 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;
// Records that some visible tab navigated (or was redirected) to the
// provided URL.
void RecordNavigation(const GURL& url);
// Checks whether navigation to the provided URL has occured in a visible
// tab recently.
bool HasRecentlyBeenNavigatedTo(const GURL& url);
// 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;
struct NavigationRecord;
// Starts scheduling periodic cleanups.
void StartSchedulingPeriodicCleanups();
// Stops scheduling periodic cleanups if they're no longer needed.
void MaybeStopSchedulingPeriodicCleanups();
// Deletes stale and cancelled prerendered PrerenderContents, as well as
// TabContents that have been replaced by prerendered TabContents.
// Also identifies and kills PrerenderContents that use too much
// resources.
void PeriodicCleanup();
// Posts a task to call PeriodicCleanup. Results in quicker destruction of
// objects. If |this| is deleted before the task is run, the task will
// automatically be cancelled.
void PostCleanupTask();
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);
// Deletes any PrerenderContents that have been added to the pending delete
// list.
void DeletePendingDeleteEntries();
// 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();
// Cleans up old NavigationRecord's.
void CleanUpOldNavigations();
// 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_;
// List of recent navigations in this profile, sorted by ascending
// navigate_time_.
std::list<NavigationRecord> navigations_;
// List of prerender elements to be deleted
std::list<PrerenderContents*> pending_delete_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_;
// Cancels pending tasks on deletion.
ScopedRunnableMethodFactory<PrerenderManager> runnable_method_factory_;
DISALLOW_COPY_AND_ASSIGN(PrerenderManager);
};
} // namespace prerender
#endif // CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_