Home | History | Annotate | Download | only in prerender
      1 // Copyright (c) 2011 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.
      4 
      5 #ifndef CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_
      6 #define CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_
      7 #pragma once
      8 
      9 #include <list>
     10 #include <map>
     11 #include <vector>
     12 
     13 #include "base/hash_tables.h"
     14 #include "base/memory/ref_counted.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "base/time.h"
     17 #include "base/timer.h"
     18 #include "chrome/browser/prerender/prerender_contents.h"
     19 #include "googleurl/src/gurl.h"
     20 
     21 class Profile;
     22 class TabContents;
     23 
     24 #if defined(COMPILER_GCC)
     25 
     26 namespace __gnu_cxx {
     27 template <>
     28 struct hash<TabContents*> {
     29   std::size_t operator()(TabContents* value) const {
     30     return reinterpret_cast<std::size_t>(value);
     31   }
     32 };
     33 }
     34 
     35 #endif
     36 
     37 namespace prerender {
     38 
     39 // PrerenderManager is responsible for initiating and keeping prerendered
     40 // views of webpages.
     41 class PrerenderManager : public base::RefCountedThreadSafe<PrerenderManager> {
     42  public:
     43   // PrerenderManagerMode is used in a UMA_HISTOGRAM, so please do not
     44   // add in the middle.
     45   enum PrerenderManagerMode {
     46     PRERENDER_MODE_DISABLED,
     47     PRERENDER_MODE_ENABLED,
     48     PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP,
     49     PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP,
     50     PRERENDER_MODE_MAX
     51   };
     52 
     53   // Owned by a Profile object for the lifetime of the profile.
     54   explicit PrerenderManager(Profile* profile);
     55 
     56   // Preloads the URL supplied.  alias_urls indicates URLs that redirect
     57   // to the same URL to be preloaded. Returns true if the URL was added,
     58   // false if it was not.
     59   bool AddPreload(const GURL& url, const std::vector<GURL>& alias_urls,
     60                   const GURL& referrer);
     61 
     62   void AddPendingPreload(const std::pair<int, int>& child_route_id_pair,
     63                          const GURL& url,
     64                          const std::vector<GURL>& alias_urls,
     65                          const GURL& referrer);
     66 
     67   // For a given TabContents that wants to navigate to the URL supplied,
     68   // determines whether a preloaded version of the URL can be used,
     69   // and substitutes the prerendered RVH into the TabContents.  Returns
     70   // whether or not a prerendered RVH could be used or not.
     71   bool MaybeUsePreloadedPage(TabContents* tc, const GURL& url);
     72 
     73   // Allows PrerenderContents to remove itself when prerendering should
     74   // be cancelled.
     75   void RemoveEntry(PrerenderContents* entry);
     76 
     77   // Retrieves the PrerenderContents object for the specified URL, if it
     78   // has been prerendered.  The caller will then have ownership of the
     79   // PrerenderContents object and is responsible for freeing it.
     80   // Returns NULL if the specified URL has not been prerendered.
     81   PrerenderContents* GetEntry(const GURL& url);
     82 
     83   // Records the perceived page load time for a page - effectively the time from
     84   // when the user navigates to a page to when it finishes loading. The actual
     85   // load may have started prior to navigation due to prerender hints.
     86   // This must be called on the UI thread.
     87   static void RecordPerceivedPageLoadTime(
     88       base::TimeDelta perceived_page_load_time,
     89       TabContents* tab_contents);
     90 
     91   // Records the time from when a page starts prerendering to when the user
     92   // navigates to it. This must be called on the UI thread.
     93   void RecordTimeUntilUsed(base::TimeDelta time_until_used);
     94 
     95   base::TimeDelta max_prerender_age() const { return max_prerender_age_; }
     96   void set_max_prerender_age(base::TimeDelta td) { max_prerender_age_ = td; }
     97   unsigned int max_elements() const { return max_elements_; }
     98   void set_max_elements(unsigned int num) { max_elements_ = num; }
     99 
    100   // Returns whether prerendering is currently enabled for this manager.
    101   // Must be called on the UI thread.
    102   bool is_enabled() const;
    103 
    104   // Set whether prerendering is currently enabled for this manager.
    105   // Must be called on the UI thread.
    106   // If |enabled| is false, existing prerendered pages will still persist until
    107   // they time out, but new ones will not be generated.
    108   void set_enabled(bool enabled);
    109 
    110   static PrerenderManagerMode GetMode();
    111   static void SetMode(PrerenderManagerMode mode);
    112   static bool IsPrerenderingPossible();
    113   static bool IsControlGroup();
    114 
    115   // The following static method can be called from any thread, but will result
    116   // in posting a task to the UI thread if we are not in the UI thread.
    117   static void RecordPrefetchTagObserved();
    118 
    119   // Maintaining and querying the set of TabContents belonging to this
    120   // PrerenderManager that are currently showing prerendered pages.
    121   void MarkTabContentsAsPrerendered(TabContents* tc);
    122   void MarkTabContentsAsWouldBePrerendered(TabContents* tc);
    123   void MarkTabContentsAsNotPrerendered(TabContents* tc);
    124   bool IsTabContentsPrerendered(TabContents* tc) const;
    125   bool WouldTabContentsBePrerendered(TabContents* tc) const;
    126 
    127   // Extracts a urlencoded URL stored in a url= query parameter from a URL
    128   // supplied, if available, and stores it in alias_url.  Returns whether or not
    129   // the operation succeeded (i.e. a valid URL was found).
    130   static bool MaybeGetQueryStringBasedAliasURL(const GURL& url,
    131                                                GURL* alias_url);
    132 
    133  protected:
    134   struct PendingContentsData;
    135 
    136   virtual ~PrerenderManager();
    137 
    138   void SetPrerenderContentsFactory(
    139       PrerenderContents::Factory* prerender_contents_factory);
    140   bool rate_limit_enabled_;
    141 
    142   PendingContentsData* FindPendingEntry(const GURL& url);
    143 
    144  private:
    145   // Test that needs needs access to internal functions.
    146   friend class PrerenderBrowserTest;
    147 
    148   friend class base::RefCountedThreadSafe<PrerenderManager>;
    149 
    150   struct PrerenderContentsData;
    151 
    152   // Starts and stops scheduling periodic cleanups, respectively.
    153   void StartSchedulingPeriodicCleanups();
    154   void StopSchedulingPeriodicCleanups();
    155 
    156   // Deletes stale prerendered PrerenderContents.
    157   // Also identifies and kills PrerenderContents that use too much
    158   // resources.
    159   void PeriodicCleanup();
    160 
    161   bool IsPrerenderElementFresh(const base::Time start) const;
    162   void DeleteOldEntries();
    163   virtual base::Time GetCurrentTime() const;
    164   virtual base::TimeTicks GetCurrentTimeTicks() const;
    165   virtual PrerenderContents* CreatePrerenderContents(
    166       const GURL& url,
    167       const std::vector<GURL>& alias_urls,
    168       const GURL& referrer);
    169 
    170   // Finds the specified PrerenderContents and returns it, if it exists.
    171   // Returns NULL otherwise.  Unlike GetEntry, the PrerenderManager maintains
    172   // ownership of the PrerenderContents.
    173   PrerenderContents* FindEntry(const GURL& url);
    174 
    175   static bool WithinWindow();
    176 
    177   static void RecordPrefetchTagObservedOnUIThread();
    178 
    179   // Called when removing a preload to ensure we clean up any pending preloads
    180   // that might remain in the map.
    181   void RemovePendingPreload(PrerenderContents* entry);
    182 
    183   bool DoesRateLimitAllowPrerender() const;
    184 
    185   // Specifies whether prerendering is currently enabled for this
    186   // manager. The value can change dynamically during the lifetime
    187   // of the PrerenderManager.
    188   bool enabled_;
    189 
    190   Profile* profile_;
    191 
    192   base::TimeDelta max_prerender_age_;
    193   unsigned int max_elements_;
    194 
    195   // List of prerendered elements.
    196   std::list<PrerenderContentsData> prerender_list_;
    197 
    198   // Set of TabContents which are currently displaying a prerendered page.
    199   base::hash_set<TabContents*> prerendered_tc_set_;
    200 
    201   // Set of TabContents which would be displaying a prerendered page
    202   // (for the control group).
    203   base::hash_set<TabContents*> would_be_prerendered_tc_set_;
    204 
    205   // Map of child/route id pairs to pending prerender data.
    206   typedef std::map<std::pair<int, int>, std::vector<PendingContentsData> >
    207       PendingPrerenderList;
    208   PendingPrerenderList pending_prerender_list_;
    209 
    210   // Default maximum permitted elements to prerender.
    211   static const unsigned int kDefaultMaxPrerenderElements = 1;
    212 
    213   // Default maximum age a prerendered element may have, in seconds.
    214   static const int kDefaultMaxPrerenderAgeSeconds = 20;
    215 
    216   // Time window for which we will record windowed PLT's from the last
    217   // observed link rel=prefetch tag.
    218   static const int kWindowDurationSeconds = 30;
    219 
    220   // Time interval at which periodic cleanups are performed.
    221   static const int kPeriodicCleanupIntervalMs = 1000;
    222 
    223   // Time interval before a new prerender is allowed.
    224   static const int kMinTimeBetweenPrerendersMs = 500;
    225 
    226   scoped_ptr<PrerenderContents::Factory> prerender_contents_factory_;
    227 
    228   static PrerenderManagerMode mode_;
    229 
    230   // The time when we last saw a prefetch request coming from a renderer.
    231   // This is used to record perceived PLT's for a certain amount of time
    232   // from the point that we last saw a <link rel=prefetch> tag.
    233   // This static variable should only be modified on the UI thread.
    234   static base::TimeTicks last_prefetch_seen_time_;
    235 
    236   // A count of how many prerenders we do per session. Initialized to 0 then
    237   // incremented and emitted to a histogram on each successful prerender.
    238   static int prerenders_per_session_count_;
    239 
    240   // RepeatingTimer to perform periodic cleanups of pending prerendered
    241   // pages.
    242   base::RepeatingTimer<PrerenderManager> repeating_timer_;
    243 
    244   // Track time of last prerender to limit prerender spam.
    245   base::TimeTicks last_prerender_start_time_;
    246 
    247   DISALLOW_COPY_AND_ASSIGN(PrerenderManager);
    248 };
    249 
    250 }  // prerender
    251 
    252 #endif  // CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_
    253