blob: bc88482899d41588c212d65c91c74b00d87414dc [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/scoped_vector.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_config.h"
#include "chrome/browser/prerender/prerender_contents.h"
#include "chrome/browser/prerender/prerender_origin.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 {
class PrerenderHistory;
class PrerenderTracker;
// 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
};
// One or more of these flags must be passed to ClearData() to specify just
// what data to clear. See function declaration for more information.
enum ClearFlags {
CLEAR_PRERENDER_CONTENTS = 0x1 << 0,
CLEAR_PRERENDER_HISTORY = 0x1 << 1,
CLEAR_MAX = 0x1 << 2
};
// ID indicating that no experiment is active.
static const uint8 kNoExperiment = 0;
// Owned by a Profile object for the lifetime of the profile.
PrerenderManager(Profile* profile, PrerenderTracker* prerender_tracker);
virtual ~PrerenderManager();
// Entry points for adding prerenders.
// Adds a prerender for |url| if valid. |process_id| and |route_id| identify
// the RenderViewHost that the prerender request came from and are 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.
// If the RenderViewHost source is itself prerendering, the prerender is added
// as a pending prerender.
bool AddPrerenderFromLinkRelPrerender(int process_id, int route_id,
const GURL& url, const GURL& referrer);
// Adds a prerender for |url| if valid. As the prerender request is coming
// from a source without a RenderViewHost (ie, the omnibox) we don't have a
// child or route id, or a referrer. This method uses sensible values for
// those.
bool AddPrerenderFromOmnibox(const GURL& url);
// Destroy all prerenders for the given child route id pair and assign a final
// status to them.
virtual void DestroyPrerenderForRenderView(int process_id, int view_id,
FinalStatus final_status);
// For a given TabContents that wants to navigate to the URL supplied,
// determines whether a prerendered 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 MaybeUsePrerenderedPage(TabContents* tab_contents,
const GURL& url,
bool has_opener_set);
// Moves a PrerenderContents to the pending delete list from the list of
// active prerenders when prerendering should be cancelled.
void MoveEntryToPendingDelete(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);
// 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();
// 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;
bool IsOldRenderViewHost(const RenderViewHost* render_view_host) const;
// Checks whether navigation to the provided URL has occured in a visible
// tab recently.
bool HasRecentlyBeenNavigatedTo(const GURL& url);
// Returns true if the method given is invalid for prerendering.
static bool IsValidHttpMethod(const std::string& method);
// Returns a Value object containing the active pages being prerendered, and
// a history of pages which were prerendered. The caller is responsible for
// deleting the return value.
base::Value* GetAsValue() const;
// Clears the data indicated by which bits of clear_flags are set.
//
// If the CLEAR_PRERENDER_CONTENTS bit is set, all active prerenders are
// cancelled and then deleted, and any TabContents queued for destruction are
// destroyed as well.
//
// If the CLEAR_PRERENDER_HISTORY bit is set, the prerender history is
// cleared, including any entries newly created by destroying them in
// response to the CLEAR_PRERENDER_CONTENTS flag.
//
// Intended to be used when clearing the cache or history.
void ClearData(int clear_flags);
// Record a final status of a prerendered page in a histogram.
void RecordFinalStatus(Origin origin,
uint8 experiment_id,
FinalStatus final_status) const;
const Config& config() const { return config_; }
Config& mutable_config() { return config_; }
protected:
// Test that needs needs access to internal functions.
FRIEND_TEST_ALL_PREFIXES(PrerenderManagerTest, ExpireTest);
FRIEND_TEST_ALL_PREFIXES(PrerenderManagerTest, ExtractURLInQueryStringTest);
struct PendingContentsData;
void SetPrerenderContentsFactory(
PrerenderContents::Factory* prerender_contents_factory);
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;
class OnCloseTabContentsDeleter;
// Adds a prerender for |url| from referrer |referrer| initiated from the
// RenderViewHost specified by |child_route_id_pair|. The |origin| specifies
// how the prerender was added.
bool AddPrerender(
Origin origin,
const std::pair<int, int>& child_route_id_pair,
const GURL& url,
const GURL& referrer);
// Adds a pending preload issued by the prerendering RenderView identified by
// |child_route_id_pair|. If and when that prerendering RenderView is used,
// the specified prerender will start.
void AddPendingPrerender(Origin origin,
const std::pair<int, int>& child_route_id_pair,
const GURL& url,
const GURL& referrer);
// 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,
Origin origin,
uint8 experiment_id);
// Checks if the PrerenderContents has been added to the pending delete list.
bool IsPendingDelete(PrerenderContents* entry) const;
// 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 prerender 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 RemovePendingPrerender(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();
// Arrange for the given tab contents to be deleted asap. If deleter is not
// NULL, deletes that as well.
void ScheduleDeleteOldTabContents(TabContentsWrapper* tab,
OnCloseTabContentsDeleter* deleter);
// Adds to the history list.
void AddToHistory(PrerenderContents* contents);
// Records that some visible tab navigated (or was redirected) to the
// provided URL.
void RecordNavigation(const GURL& url);
// Returns a new Value representing the pages currently being prerendered. The
// caller is responsible for delete'ing the return value.
base::Value* GetActivePrerendersAsValue() const;
// Destroys all pending prerenders using FinalStatus. Also deletes them as
// well as any swapped out TabContents queued for destruction.
// Used both on destruction, and when clearing the browing history.
void DestroyAllContents(FinalStatus final_status);
// 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);
// Composes a histogram name based on a histogram type.
std::string ComposeHistogramName(const std::string& prefix_type,
const std::string& name) const;
// Returns the histogram name for a given origin and experiment.
std::string GetHistogramName(Origin origin, uint8 experiment_id,
const std::string& name) const;
// Returns the histogram name for the current window.
std::string GetDefaultHistogramName(const std::string& name) const;
// Returns the current experiment.
uint8 GetCurrentExperimentId() const;
// Returns the current origin.
Origin GetCurrentOrigin() const;
// Returns whether or not there is currently an origin/experiment wash.
bool IsOriginExperimentWash() const;
// The configuration.
Config config_;
// Specifies whether prerendering is currently enabled for this
// manager. The value can change dynamically during the lifetime
// of the PrerenderManager.
bool enabled_;
// The profile that owns this PrerenderManager.
Profile* profile_;
PrerenderTracker* prerender_tracker_;
// 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_;
// An integer indicating a Prerendering Experiment being currently conducted.
// (The last experiment ID seen).
uint8 last_experiment_id_;
// Origin of the last prerender seen.
Origin last_origin_;
// A boolean indicating that we have recently encountered a combination of
// different experiments and origins, making an attribution of PPLT's to
// experiments / origins impossible.
bool origin_experiment_wash_;
// The time when we last saw a prerender 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=prerender> tag.
base::TimeTicks last_prerender_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_;
ScopedVector<OnCloseTabContentsDeleter> on_close_tab_contents_deleters_;
scoped_ptr<PrerenderHistory> prerender_history_;
DISALLOW_COPY_AND_ASSIGN(PrerenderManager);
};
} // namespace prerender
#endif // CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_