| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/browser/prerender/prerender_local_predictor.h" | 5 #include "chrome/browser/prerender/prerender_local_predictor.h" | 
| 6 | 6 | 
| 7 #include <ctype.h> | 7 #include <ctype.h> | 
| 8 | 8 | 
| 9 #include <algorithm> | 9 #include <algorithm> | 
| 10 #include <map> | 10 #include <map> | 
| 11 #include <set> | 11 #include <set> | 
| 12 #include <string> | 12 #include <string> | 
| 13 #include <utility> | 13 #include <utility> | 
| 14 | 14 | 
| 15 #include "base/metrics/field_trial.h" | 15 #include "base/metrics/field_trial.h" | 
| 16 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" | 
| 17 #include "base/timer.h" | 17 #include "base/timer.h" | 
| 18 #include "chrome/browser/history/history_database.h" | 18 #include "chrome/browser/history/history_database.h" | 
| 19 #include "chrome/browser/history/history_db_task.h" | 19 #include "chrome/browser/history/history_db_task.h" | 
| 20 #include "chrome/browser/history/history_service.h" | 20 #include "chrome/browser/history/history_service.h" | 
| 21 #include "chrome/browser/history/history_service_factory.h" | 21 #include "chrome/browser/history/history_service_factory.h" | 
|  | 22 #include "chrome/browser/prerender/prerender_handle.h" | 
| 22 #include "chrome/browser/prerender/prerender_histograms.h" | 23 #include "chrome/browser/prerender/prerender_histograms.h" | 
| 23 #include "chrome/browser/prerender/prerender_manager.h" | 24 #include "chrome/browser/prerender/prerender_manager.h" | 
| 24 #include "chrome/browser/profiles/profile.h" | 25 #include "chrome/browser/profiles/profile.h" | 
|  | 26 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" | 
| 25 #include "content/public/browser/browser_thread.h" | 27 #include "content/public/browser/browser_thread.h" | 
|  | 28 #include "content/public/browser/navigation_controller.h" | 
|  | 29 #include "content/public/browser/session_storage_namespace.h" | 
|  | 30 #include "content/public/browser/web_contents.h" | 
|  | 31 #include "content/public/browser/web_contents_view.h" | 
| 26 #include "content/public/common/page_transition_types.h" | 32 #include "content/public/common/page_transition_types.h" | 
| 27 #include "crypto/secure_hash.h" | 33 #include "crypto/secure_hash.h" | 
|  | 34 #include "googleurl/src/url_canon.h" | 
| 28 #include "grit/browser_resources.h" | 35 #include "grit/browser_resources.h" | 
| 29 #include "ui/base/resource/resource_bundle.h" | 36 #include "ui/base/resource/resource_bundle.h" | 
| 30 | 37 | 
| 31 using content::BrowserThread; | 38 using content::BrowserThread; | 
| 32 using content::PageTransition; | 39 using content::PageTransition; | 
|  | 40 using content::SessionStorageNamespace; | 
|  | 41 using content::WebContents; | 
| 33 using history::URLID; | 42 using history::URLID; | 
|  | 43 using predictors::LoggedInPredictorTable; | 
|  | 44 using std::string; | 
|  | 45 using std::vector; | 
| 34 | 46 | 
| 35 namespace prerender { | 47 namespace prerender { | 
| 36 | 48 | 
| 37 namespace { | 49 namespace { | 
| 38 | 50 | 
| 39 static const size_t kURLHashSize = 5; | 51 static const size_t kURLHashSize = 5; | 
|  | 52 static const int kNumPrerenderCandidates = 5; | 
|  | 53 | 
|  | 54 }  // namespace | 
|  | 55 | 
|  | 56 // When considering a candidate URL to be prerendered, we need to collect the | 
|  | 57 // data in this struct to make the determination whether we should issue the | 
|  | 58 // prerender or not. | 
|  | 59 struct PrerenderLocalPredictor::LocalPredictorURLInfo { | 
|  | 60   URLID id; | 
|  | 61   GURL url; | 
|  | 62   bool url_lookup_success; | 
|  | 63   bool logged_in; | 
|  | 64   bool logged_in_lookup_ok; | 
|  | 65   double priority; | 
|  | 66 }; | 
|  | 67 | 
|  | 68 // A struct consisting of everything needed for launching a potential prerender | 
|  | 69 // on a navigation: The navigation URL (source) triggering potential prerenders, | 
|  | 70 // and a set of candidate URLs. | 
|  | 71 struct PrerenderLocalPredictor::LocalPredictorURLLookupInfo { | 
|  | 72   LocalPredictorURLInfo source_url_; | 
|  | 73   vector<LocalPredictorURLInfo> candidate_urls_; | 
|  | 74   explicit LocalPredictorURLLookupInfo(URLID source_id) { | 
|  | 75     source_url_.id = source_id; | 
|  | 76   } | 
|  | 77   void MaybeAddCandidateURL(URLID id, double priority) { | 
|  | 78     // TODO(tburkard): clean up this code, potentially using a list or a heap | 
|  | 79     LocalPredictorURLInfo info; | 
|  | 80     info.id = id; | 
|  | 81     info.priority = priority; | 
|  | 82     int insert_pos = candidate_urls_.size(); | 
|  | 83     if (insert_pos < kNumPrerenderCandidates) | 
|  | 84       candidate_urls_.push_back(info); | 
|  | 85     while (insert_pos > 0 && | 
|  | 86            candidate_urls_[insert_pos - 1].priority < info.priority) { | 
|  | 87       if (insert_pos < kNumPrerenderCandidates) | 
|  | 88         candidate_urls_[insert_pos] = candidate_urls_[insert_pos - 1]; | 
|  | 89       insert_pos--; | 
|  | 90     } | 
|  | 91     if (insert_pos < kNumPrerenderCandidates) | 
|  | 92       candidate_urls_[insert_pos] = info; | 
|  | 93   } | 
|  | 94 }; | 
|  | 95 | 
|  | 96 namespace { | 
| 40 | 97 | 
| 41 // Task to lookup the URL for a given URLID. | 98 // Task to lookup the URL for a given URLID. | 
| 42 class GetURLForURLIDTask : public history::HistoryDBTask { | 99 class GetURLForURLIDTask : public history::HistoryDBTask { | 
| 43  public: | 100  public: | 
| 44   GetURLForURLIDTask(URLID url_id, base::Callback<void(const GURL&)> callback) | 101   GetURLForURLIDTask( | 
| 45       : url_id_(url_id), | 102       PrerenderLocalPredictor::LocalPredictorURLLookupInfo* request, | 
| 46         success_(false), | 103       const base::Closure& callback) | 
|  | 104       : request_(request), | 
| 47         callback_(callback), | 105         callback_(callback), | 
| 48         start_time_(base::Time::Now()) { | 106         start_time_(base::Time::Now()) { | 
| 49   } | 107   } | 
| 50 | 108 | 
| 51   virtual bool RunOnDBThread(history::HistoryBackend* backend, | 109   virtual bool RunOnDBThread(history::HistoryBackend* backend, | 
| 52                              history::HistoryDatabase* db) OVERRIDE { | 110                              history::HistoryDatabase* db) OVERRIDE { | 
| 53     history::URLRow url_row; | 111     DoURLLookup(db, &request_->source_url_); | 
| 54     success_ = db->GetURLRow(url_id_, &url_row); | 112     for (int i = 0; i < static_cast<int>(request_->candidate_urls_.size()); i++) | 
| 55     if (success_) | 113       DoURLLookup(db, &request_->candidate_urls_[i]); | 
| 56       url_ = url_row.url(); |  | 
| 57     return true; | 114     return true; | 
| 58   } | 115   } | 
| 59 | 116 | 
| 60   virtual void DoneRunOnMainThread() OVERRIDE { | 117   virtual void DoneRunOnMainThread() OVERRIDE { | 
| 61     if (success_) { | 118     callback_.Run(); | 
| 62       callback_.Run(url_); | 119     UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.LocalPredictorURLLookupTime", | 
| 63       UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.LocalPredictorURLLookupTime", | 120                                base::Time::Now() - start_time_, | 
| 64                                  base::Time::Now() - start_time_, | 121                                base::TimeDelta::FromMilliseconds(10), | 
| 65                                  base::TimeDelta::FromMilliseconds(10), | 122                                base::TimeDelta::FromSeconds(10), | 
| 66                                  base::TimeDelta::FromSeconds(10), | 123                                50); | 
| 67                                  50); |  | 
| 68     } |  | 
| 69   } | 124   } | 
| 70 | 125 | 
| 71  private: | 126  private: | 
| 72   virtual ~GetURLForURLIDTask() {} | 127   virtual ~GetURLForURLIDTask() {} | 
| 73 | 128 | 
| 74   URLID url_id_; | 129   void DoURLLookup(history::HistoryDatabase* db, | 
| 75   bool success_; | 130                    PrerenderLocalPredictor::LocalPredictorURLInfo* request) { | 
| 76   base::Callback<void(const GURL&)> callback_; | 131     history::URLRow url_row; | 
|  | 132     request->url_lookup_success = db->GetURLRow(request->id, &url_row); | 
|  | 133     if (request->url_lookup_success) | 
|  | 134       request->url = url_row.url(); | 
|  | 135   } | 
|  | 136 | 
|  | 137   PrerenderLocalPredictor::LocalPredictorURLLookupInfo* request_; | 
|  | 138   base::Closure callback_; | 
| 77   base::Time start_time_; | 139   base::Time start_time_; | 
| 78   GURL url_; |  | 
| 79   DISALLOW_COPY_AND_ASSIGN(GetURLForURLIDTask); | 140   DISALLOW_COPY_AND_ASSIGN(GetURLForURLIDTask); | 
| 80 }; | 141 }; | 
| 81 | 142 | 
| 82 // Task to load history from the visit database on startup. | 143 // Task to load history from the visit database on startup. | 
| 83 class GetVisitHistoryTask : public history::HistoryDBTask { | 144 class GetVisitHistoryTask : public history::HistoryDBTask { | 
| 84  public: | 145  public: | 
| 85   GetVisitHistoryTask(PrerenderLocalPredictor* local_predictor, | 146   GetVisitHistoryTask(PrerenderLocalPredictor* local_predictor, | 
| 86                       int max_visits) | 147                       int max_visits) | 
| 87       : local_predictor_(local_predictor), | 148       : local_predictor_(local_predictor), | 
| 88         max_visits_(max_visits), | 149         max_visits_(max_visits), | 
| 89         visit_history_(new std::vector<history::BriefVisitInfo>) { | 150         visit_history_(new vector<history::BriefVisitInfo>) { | 
| 90   } | 151   } | 
| 91 | 152 | 
| 92   virtual bool RunOnDBThread(history::HistoryBackend* backend, | 153   virtual bool RunOnDBThread(history::HistoryBackend* backend, | 
| 93                              history::HistoryDatabase* db) OVERRIDE { | 154                              history::HistoryDatabase* db) OVERRIDE { | 
| 94     db->GetBriefVisitInfoOfMostRecentVisits(max_visits_, visit_history_.get()); | 155     db->GetBriefVisitInfoOfMostRecentVisits(max_visits_, visit_history_.get()); | 
| 95     return true; | 156     return true; | 
| 96   } | 157   } | 
| 97 | 158 | 
| 98   virtual void DoneRunOnMainThread() OVERRIDE { | 159   virtual void DoneRunOnMainThread() OVERRIDE { | 
| 99     local_predictor_->OnGetInitialVisitHistory(visit_history_.Pass()); | 160     local_predictor_->OnGetInitialVisitHistory(visit_history_.Pass()); | 
| 100   } | 161   } | 
| 101 | 162 | 
| 102  private: | 163  private: | 
| 103   virtual ~GetVisitHistoryTask() {} | 164   virtual ~GetVisitHistoryTask() {} | 
| 104 | 165 | 
| 105   PrerenderLocalPredictor* local_predictor_; | 166   PrerenderLocalPredictor* local_predictor_; | 
| 106   int max_visits_; | 167   int max_visits_; | 
| 107   scoped_ptr<std::vector<history::BriefVisitInfo> > visit_history_; | 168   scoped_ptr<vector<history::BriefVisitInfo> > visit_history_; | 
| 108   DISALLOW_COPY_AND_ASSIGN(GetVisitHistoryTask); | 169   DISALLOW_COPY_AND_ASSIGN(GetVisitHistoryTask); | 
| 109 }; | 170 }; | 
| 110 | 171 | 
| 111 // Maximum visit history to retrieve from the visit database. | 172 // Maximum visit history to retrieve from the visit database. | 
| 112 const int kMaxVisitHistory = 100 * 1000; | 173 const int kMaxVisitHistory = 100 * 1000; | 
| 113 | 174 | 
| 114 // Visit history size at which to trigger pruning, and number of items to prune. | 175 // Visit history size at which to trigger pruning, and number of items to prune. | 
| 115 const int kVisitHistoryPruneThreshold = 120 * 1000; | 176 const int kVisitHistoryPruneThreshold = 120 * 1000; | 
| 116 const int kVisitHistoryPruneAmount = 20 * 1000; | 177 const int kVisitHistoryPruneAmount = 20 * 1000; | 
| 117 | 178 | 
| 118 const int kMaxLocalPredictionTimeMs = 300 * 1000; | 179 const int kMaxLocalPredictionTimeMs = 180 * 1000; | 
| 119 const int kMinLocalPredictionTimeMs = 500; | 180 const int kMinLocalPredictionTimeMs = 500; | 
| 120 | 181 | 
| 121 bool IsBackForward(PageTransition transition) { | 182 bool IsBackForward(PageTransition transition) { | 
| 122   return (transition & content::PAGE_TRANSITION_FORWARD_BACK) != 0; | 183   return (transition & content::PAGE_TRANSITION_FORWARD_BACK) != 0; | 
| 123 } | 184 } | 
| 124 | 185 | 
| 125 bool IsHomePage(PageTransition transition) { | 186 bool IsHomePage(PageTransition transition) { | 
| 126   return (transition & content::PAGE_TRANSITION_HOME_PAGE) != 0; | 187   return (transition & content::PAGE_TRANSITION_HOME_PAGE) != 0; | 
| 127 } | 188 } | 
| 128 | 189 | 
| 129 bool IsIntermediateRedirect(PageTransition transition) { | 190 bool IsIntermediateRedirect(PageTransition transition) { | 
| 130   return (transition & content::PAGE_TRANSITION_CHAIN_END) == 0; | 191   return (transition & content::PAGE_TRANSITION_CHAIN_END) == 0; | 
| 131 } | 192 } | 
| 132 | 193 | 
| 133 bool ShouldExcludeTransitionForPrediction(PageTransition transition) { | 194 bool ShouldExcludeTransitionForPrediction(PageTransition transition) { | 
| 134   return IsBackForward(transition) || IsHomePage(transition) || | 195   return IsBackForward(transition) || IsHomePage(transition) || | 
| 135       IsIntermediateRedirect(transition); | 196       IsIntermediateRedirect(transition); | 
| 136 } | 197 } | 
| 137 | 198 | 
| 138 base::Time GetCurrentTime() { | 199 base::Time GetCurrentTime() { | 
| 139   return base::Time::Now(); | 200   return base::Time::Now(); | 
| 140 } | 201 } | 
| 141 | 202 | 
| 142 bool StrCaseStr(std::string haystack, std::string needle) { | 203 bool StringContainsIgnoringCase(string haystack, string needle) { | 
| 143   std::transform(haystack.begin(), haystack.end(), haystack.begin(), ::tolower); | 204   std::transform(haystack.begin(), haystack.end(), haystack.begin(), ::tolower); | 
| 144   std::transform(needle.begin(), needle.end(), needle.begin(), ::tolower); | 205   std::transform(needle.begin(), needle.end(), needle.begin(), ::tolower); | 
| 145   return haystack.find(needle) != std::string::npos; | 206   return haystack.find(needle) != string::npos; | 
| 146 } | 207 } | 
| 147 | 208 | 
| 148 bool IsExtendedRootURL(const GURL& url) { | 209 bool IsExtendedRootURL(const GURL& url) { | 
| 149   const std::string& path = url.path(); | 210   const string& path = url.path(); | 
| 150   return path == "/index.html" || path == "/home.html" || | 211   return path == "/index.html" || path == "/home.html" || | 
| 151       path == "/main.html" || | 212       path == "/main.html" || | 
| 152       path == "/index.htm" || path == "/home.htm" || path == "/main.htm" || | 213       path == "/index.htm" || path == "/home.htm" || path == "/main.htm" || | 
| 153       path == "/index.php" || path == "/home.php" || path == "/main.php" || | 214       path == "/index.php" || path == "/home.php" || path == "/main.php" || | 
| 154       path == "/index.asp" || path == "/home.asp" || path == "/main.asp" || | 215       path == "/index.asp" || path == "/home.asp" || path == "/main.asp" || | 
| 155       path == "/index.py" || path == "/home.py" || path == "/main.py" || | 216       path == "/index.py" || path == "/home.py" || path == "/main.py" || | 
| 156       path == "/index.pl" || path == "/home.pl" || path == "/main.pl"; | 217       path == "/index.pl" || path == "/home.pl" || path == "/main.pl"; | 
| 157 } | 218 } | 
| 158 | 219 | 
| 159 bool IsRootPageURL(const GURL& url) { | 220 bool IsRootPageURL(const GURL& url) { | 
| 160   return (url.path() == "/" || url.path() == "" || IsExtendedRootURL(url)) && | 221   return (url.path() == "/" || url.path() == "" || IsExtendedRootURL(url)) && | 
| 161       (!url.has_query()) && (!url.has_ref()); | 222       (!url.has_query()) && (!url.has_ref()); | 
| 162 } | 223 } | 
| 163 | 224 | 
|  | 225 bool IsLogInURL(const GURL& url) { | 
|  | 226   return StringContainsIgnoringCase(url.spec().c_str(), "login") || | 
|  | 227       StringContainsIgnoringCase(url.spec().c_str(), "signin"); | 
|  | 228 } | 
|  | 229 | 
|  | 230 bool IsLogOutURL(const GURL& url) { | 
|  | 231   return StringContainsIgnoringCase(url.spec().c_str(), "logout") || | 
|  | 232       StringContainsIgnoringCase(url.spec().c_str(), "signout"); | 
|  | 233 } | 
|  | 234 | 
| 164 int64 URLHashToInt64(const unsigned char* data) { | 235 int64 URLHashToInt64(const unsigned char* data) { | 
| 165   COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64); | 236   COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64); | 
| 166   int64 value = 0; | 237   int64 value = 0; | 
| 167   memcpy(&value, data, kURLHashSize); | 238   memcpy(&value, data, kURLHashSize); | 
| 168   return value; | 239   return value; | 
| 169 } | 240 } | 
| 170 | 241 | 
| 171 int64 GetInt64URLHashForURL(const GURL& url) { | 242 int64 GetInt64URLHashForURL(const GURL& url) { | 
| 172   COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64); | 243   COMPILE_ASSERT(kURLHashSize < sizeof(int64), url_hash_must_fit_in_int64); | 
| 173   scoped_ptr<crypto::SecureHash> hash( | 244   scoped_ptr<crypto::SecureHash> hash( | 
| 174       crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | 245       crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | 
| 175   int64 hash_value = 0; | 246   int64 hash_value = 0; | 
| 176   const char* url_string = url.spec().c_str(); | 247   const char* url_string = url.spec().c_str(); | 
| 177   hash->Update(url_string, strlen(url_string)); | 248   hash->Update(url_string, strlen(url_string)); | 
| 178   hash->Finish(&hash_value, kURLHashSize); | 249   hash->Finish(&hash_value, kURLHashSize); | 
| 179   return hash_value; | 250   return hash_value; | 
| 180 } | 251 } | 
| 181 | 252 | 
|  | 253 bool URLsIdenticalIgnoringFragments(const GURL& url1, const GURL& url2) { | 
|  | 254   url_canon::Replacements<char> replacement; | 
|  | 255   replacement.ClearRef(); | 
|  | 256   GURL u1 = url1.ReplaceComponents(replacement); | 
|  | 257   GURL u2 = url2.ReplaceComponents(replacement); | 
|  | 258   return (u1 == u2); | 
|  | 259 } | 
|  | 260 | 
|  | 261 void LookupLoggedInStatesOnDBThread( | 
|  | 262     scoped_refptr<LoggedInPredictorTable> logged_in_predictor_table, | 
|  | 263     PrerenderLocalPredictor::LocalPredictorURLLookupInfo* request_) { | 
|  | 264   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 
|  | 265   for (int i = 0; i < static_cast<int>(request_->candidate_urls_.size()); i++) { | 
|  | 266     PrerenderLocalPredictor::LocalPredictorURLInfo* info = | 
|  | 267         &request_->candidate_urls_[i]; | 
|  | 268     if (info->url_lookup_success) { | 
|  | 269       logged_in_predictor_table->HasUserLoggedIn( | 
|  | 270           info->url, &info->logged_in, &info->logged_in_lookup_ok); | 
|  | 271     } else { | 
|  | 272       info->logged_in_lookup_ok = false; | 
|  | 273     } | 
|  | 274   } | 
|  | 275 } | 
|  | 276 | 
| 182 }  // namespace | 277 }  // namespace | 
| 183 | 278 | 
| 184 struct PrerenderLocalPredictor::PrerenderData { | 279 struct PrerenderLocalPredictor::PrerenderProperties { | 
| 185   PrerenderData(URLID url_id, const GURL& url, double priority, | 280   PrerenderProperties(URLID url_id, const GURL& url, double priority, | 
| 186                 base::Time start_time) | 281                 base::Time start_time) | 
| 187       : url_id(url_id), | 282       : url_id(url_id), | 
| 188         url(url), | 283         url(url), | 
| 189         priority(priority), | 284         priority(priority), | 
| 190         start_time(start_time) { | 285         start_time(start_time) { | 
| 191   } | 286   } | 
| 192 | 287 | 
| 193   URLID url_id; | 288   URLID url_id; | 
| 194   GURL url; | 289   GURL url; | 
| 195   double priority; | 290   double priority; | 
| 196   // For expiration purposes, this is a synthetic start time consisting either | 291   // For expiration purposes, this is a synthetic start time consisting either | 
| 197   // of the actual start time, or of the last time the page was re-requested | 292   // of the actual start time, or of the last time the page was re-requested | 
| 198   // for prerendering - 10 seconds (unless the original request came after | 293   // for prerendering - 10 seconds (unless the original request came after | 
| 199   // that).  This is to emulate the effect of re-prerendering a page that is | 294   // that).  This is to emulate the effect of re-prerendering a page that is | 
| 200   // about to expire, because it was re-requested for prerendering a second | 295   // about to expire, because it was re-requested for prerendering a second | 
| 201   // time after the actual prerender being kept around. | 296   // time after the actual prerender being kept around. | 
| 202   base::Time start_time; | 297   base::Time start_time; | 
| 203   // The actual time this page was last requested for prerendering. | 298   // The actual time this page was last requested for prerendering. | 
| 204   base::Time actual_start_time; | 299   base::Time actual_start_time; | 
| 205 | 300 | 
| 206  private: | 301  private: | 
| 207   DISALLOW_IMPLICIT_CONSTRUCTORS(PrerenderData); | 302   DISALLOW_IMPLICIT_CONSTRUCTORS(PrerenderProperties); | 
| 208 }; | 303 }; | 
| 209 | 304 | 
| 210 PrerenderLocalPredictor::PrerenderLocalPredictor( | 305 PrerenderLocalPredictor::PrerenderLocalPredictor( | 
| 211     PrerenderManager* prerender_manager) | 306     PrerenderManager* prerender_manager) | 
| 212     : prerender_manager_(prerender_manager), | 307     : prerender_manager_(prerender_manager), | 
| 213       is_visit_database_observer_(false) { | 308       is_visit_database_observer_(false), | 
|  | 309       weak_factory_(this) { | 
| 214   RecordEvent(EVENT_CONSTRUCTED); | 310   RecordEvent(EVENT_CONSTRUCTED); | 
| 215   if (MessageLoop::current()) { | 311   if (MessageLoop::current()) { | 
| 216     timer_.Start(FROM_HERE, | 312     timer_.Start(FROM_HERE, | 
| 217                  base::TimeDelta::FromMilliseconds(kInitDelayMs), | 313                  base::TimeDelta::FromMilliseconds(kInitDelayMs), | 
| 218                  this, | 314                  this, | 
| 219                  &PrerenderLocalPredictor::Init); | 315                  &PrerenderLocalPredictor::Init); | 
| 220     RecordEvent(EVENT_INIT_SCHEDULED); | 316     RecordEvent(EVENT_INIT_SCHEDULED); | 
| 221   } | 317   } | 
| 222 | 318 | 
| 223   static const size_t kChecksumHashSize = 32; | 319   static const size_t kChecksumHashSize = 32; | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 243   for (const unsigned char* p = front + kChecksumHashSize; | 339   for (const unsigned char* p = front + kChecksumHashSize; | 
| 244        p < front + size; | 340        p < front + size; | 
| 245        p += kURLHashSize) { | 341        p += kURLHashSize) { | 
| 246     url_whitelist_.insert(URLHashToInt64(p)); | 342     url_whitelist_.insert(URLHashToInt64(p)); | 
| 247   } | 343   } | 
| 248   RecordEvent(EVENT_URL_WHITELIST_OK); | 344   RecordEvent(EVENT_URL_WHITELIST_OK); | 
| 249 } | 345 } | 
| 250 | 346 | 
| 251 PrerenderLocalPredictor::~PrerenderLocalPredictor() { | 347 PrerenderLocalPredictor::~PrerenderLocalPredictor() { | 
| 252   Shutdown(); | 348   Shutdown(); | 
|  | 349   if (prerender_handle_.get()) | 
|  | 350     prerender_handle_->OnCancel(); | 
| 253 } | 351 } | 
| 254 | 352 | 
| 255 void PrerenderLocalPredictor::Shutdown() { | 353 void PrerenderLocalPredictor::Shutdown() { | 
| 256   timer_.Stop(); | 354   timer_.Stop(); | 
| 257   if (is_visit_database_observer_) { | 355   if (is_visit_database_observer_) { | 
| 258     HistoryService* history = GetHistoryIfExists(); | 356     HistoryService* history = GetHistoryIfExists(); | 
| 259     CHECK(history); | 357     CHECK(history); | 
| 260     history->RemoveVisitDatabaseObserver(this); | 358     history->RemoveVisitDatabaseObserver(this); | 
| 261     is_visit_database_observer_ = false; | 359     is_visit_database_observer_ = false; | 
| 262   } | 360   } | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 289     return; | 387     return; | 
| 290   RecordEvent(EVENT_ADD_VISIT_RELEVANT_TRANSITION); | 388   RecordEvent(EVENT_ADD_VISIT_RELEVANT_TRANSITION); | 
| 291   base::TimeDelta max_age = | 389   base::TimeDelta max_age = | 
| 292       base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs); | 390       base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs); | 
| 293   base::TimeDelta min_age = | 391   base::TimeDelta min_age = | 
| 294       base::TimeDelta::FromMilliseconds(kMinLocalPredictionTimeMs); | 392       base::TimeDelta::FromMilliseconds(kMinLocalPredictionTimeMs); | 
| 295   std::set<URLID> next_urls_currently_found; | 393   std::set<URLID> next_urls_currently_found; | 
| 296   std::map<URLID, int> next_urls_num_found; | 394   std::map<URLID, int> next_urls_num_found; | 
| 297   int num_occurrences_of_current_visit = 0; | 395   int num_occurrences_of_current_visit = 0; | 
| 298   base::Time last_visited; | 396   base::Time last_visited; | 
| 299   URLID best_next_url = 0; | 397   scoped_ptr<LocalPredictorURLLookupInfo> lookup_info( | 
| 300   int best_next_url_count = 0; | 398       new LocalPredictorURLLookupInfo(info.url_id)); | 
| 301   const std::vector<history::BriefVisitInfo>& visits = *(visit_history_.get()); | 399   const vector<history::BriefVisitInfo>& visits = *(visit_history_.get()); | 
| 302   for (int i = 0; i < static_cast<int>(visits.size()); i++) { | 400   for (int i = 0; i < static_cast<int>(visits.size()); i++) { | 
| 303     if (!ShouldExcludeTransitionForPrediction(visits[i].transition)) { | 401     if (!ShouldExcludeTransitionForPrediction(visits[i].transition)) { | 
| 304       if (visits[i].url_id == info.url_id) { | 402       if (visits[i].url_id == info.url_id) { | 
| 305         last_visited = visits[i].time; | 403         last_visited = visits[i].time; | 
| 306         num_occurrences_of_current_visit++; | 404         num_occurrences_of_current_visit++; | 
| 307         next_urls_currently_found.clear(); | 405         next_urls_currently_found.clear(); | 
| 308         continue; | 406         continue; | 
| 309       } | 407       } | 
| 310       if (!last_visited.is_null() && | 408       if (!last_visited.is_null() && | 
| 311           last_visited > visits[i].time - max_age && | 409           last_visited > visits[i].time - max_age && | 
| 312           last_visited < visits[i].time - min_age) { | 410           last_visited < visits[i].time - min_age) { | 
| 313         next_urls_currently_found.insert(visits[i].url_id); | 411         next_urls_currently_found.insert(visits[i].url_id); | 
| 314       } | 412       } | 
| 315     } | 413     } | 
| 316     if (i == static_cast<int>(visits.size()) - 1 || | 414     if (i == static_cast<int>(visits.size()) - 1 || | 
| 317         visits[i+1].url_id == info.url_id) { | 415         visits[i+1].url_id == info.url_id) { | 
| 318       for (std::set<URLID>::iterator it = next_urls_currently_found.begin(); | 416       for (std::set<URLID>::iterator it = next_urls_currently_found.begin(); | 
| 319            it != next_urls_currently_found.end(); | 417            it != next_urls_currently_found.end(); | 
| 320            ++it) { | 418            ++it) { | 
| 321         std::pair<std::map<URLID, int>::iterator, bool> insert_ret = | 419         std::pair<std::map<URLID, int>::iterator, bool> insert_ret = | 
| 322             next_urls_num_found.insert(std::pair<URLID, int>(*it, 0)); | 420             next_urls_num_found.insert(std::pair<URLID, int>(*it, 0)); | 
| 323         std::map<URLID, int>::iterator num_found_it = insert_ret.first; | 421         std::map<URLID, int>::iterator num_found_it = insert_ret.first; | 
| 324         num_found_it->second++; | 422         num_found_it->second++; | 
| 325         if (num_found_it->second > best_next_url_count) { |  | 
| 326           best_next_url_count = num_found_it->second; |  | 
| 327           best_next_url = *it; |  | 
| 328         } |  | 
| 329       } | 423       } | 
| 330     } | 424     } | 
| 331   } | 425   } | 
| 332 | 426 | 
| 333   // Only consider a candidate next page for prerendering if it was viewed | 427   for (std::map<URLID, int>::const_iterator it = next_urls_num_found.begin(); | 
| 334   // at least twice, and at least 10% of the time. | 428        it != next_urls_num_found.end(); | 
| 335   if (num_occurrences_of_current_visit > 0 && | 429        ++it) { | 
| 336       best_next_url_count > 1 && | 430     // Only consider a candidate next page for prerendering if it was viewed | 
| 337       best_next_url_count * 10 >= num_occurrences_of_current_visit) { | 431     // at least twice, and at least 10% of the time. | 
| 338     RecordEvent(EVENT_ADD_VISIT_IDENTIFIED_PRERENDER_CANDIDATE); | 432     if (num_occurrences_of_current_visit > 0 && | 
| 339     double priority = static_cast<double>(best_next_url_count) / | 433         it->second > 1 && | 
| 340         static_cast<double>(num_occurrences_of_current_visit); | 434         it->second * 10 >= num_occurrences_of_current_visit) { | 
| 341     if (ShouldReplaceCurrentPrerender(priority)) { | 435       RecordEvent(EVENT_ADD_VISIT_IDENTIFIED_PRERENDER_CANDIDATE); | 
| 342       RecordEvent(EVENT_START_URL_LOOKUP); | 436       double priority = static_cast<double>(it->second) / | 
| 343       HistoryService* history = GetHistoryIfExists(); | 437           static_cast<double>(num_occurrences_of_current_visit); | 
| 344       if (history) { | 438       lookup_info->MaybeAddCandidateURL(it->first, priority); | 
| 345         history->ScheduleDBTask( |  | 
| 346             new GetURLForURLIDTask( |  | 
| 347                 best_next_url, |  | 
| 348                 base::Bind(&PrerenderLocalPredictor::OnLookupURL, |  | 
| 349                            base::Unretained(this), |  | 
| 350                            best_next_url, |  | 
| 351                            priority)), |  | 
| 352             &history_db_consumer_); |  | 
| 353       } |  | 
| 354     } | 439     } | 
| 355   } | 440   } | 
|  | 441 | 
|  | 442   if (lookup_info->candidate_urls_.size() == 0) { | 
|  | 443     RecordEvent(EVENT_NO_PRERENDER_CANDIDATES); | 
|  | 444     return; | 
|  | 445   } | 
|  | 446 | 
|  | 447   RecordEvent(EVENT_START_URL_LOOKUP); | 
|  | 448   HistoryService* history = GetHistoryIfExists(); | 
|  | 449   if (history) { | 
|  | 450     RecordEvent(EVENT_GOT_HISTORY_ISSUING_LOOKUP); | 
|  | 451     LocalPredictorURLLookupInfo* lookup_info_ptr = lookup_info.get(); | 
|  | 452     history->ScheduleDBTask( | 
|  | 453         new GetURLForURLIDTask( | 
|  | 454             lookup_info_ptr, | 
|  | 455             base::Bind(&PrerenderLocalPredictor::OnLookupURL, | 
|  | 456                        base::Unretained(this), | 
|  | 457                        base::Passed(&lookup_info))), | 
|  | 458         &history_db_consumer_); | 
|  | 459   } | 
| 356 } | 460 } | 
| 357 | 461 | 
| 358 void PrerenderLocalPredictor::OnLookupURL(history::URLID url_id, | 462 void PrerenderLocalPredictor::OnLookupURL( | 
| 359                                           double priority, | 463     scoped_ptr<LocalPredictorURLLookupInfo> info) { | 
| 360                                           const GURL& url) { |  | 
| 361   RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT); | 464   RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT); | 
| 362 | 465 | 
| 363   base::Time current_time = GetCurrentTime(); | 466   DCHECK_GE(static_cast<int>(info->candidate_urls_.size()), 1); | 
| 364   if (ShouldReplaceCurrentPrerender(priority)) { | 467 | 
| 365     if (IsRootPageURL(url)) { | 468   if (!info->source_url_.url_lookup_success) { | 
| 366       RecordEvent(EVENT_ADD_VISIT_PRERENDERING); | 469     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_FAILED); | 
| 367       if (current_prerender_.get() && current_prerender_->url_id == url_id) { | 470     return; | 
| 368         RecordEvent(EVENT_ADD_VISIT_PRERENDERING_EXTENDED); | 471   } | 
| 369         if (priority > current_prerender_->priority) | 472 | 
| 370           current_prerender_->priority = priority; | 473   LogCandidateURLStats(info->candidate_urls_[0].url); | 
| 371         // If the prerender already existed, we want to extend it.  However, | 474 | 
| 372         // we do not want to set its start_time to the current time to | 475   WebContents* source_web_contents = NULL; | 
| 373         // disadvantage PLT computations when the prerender is swapped in. | 476 | 
| 374         // So we set the new start time to current_time - 10s (since the vast | 477 #if !defined(OS_ANDROID) | 
| 375         // majority of PLTs are < 10s), provided that is not before the actual | 478   // We need to figure out what tab launched the prerender. We do this by | 
| 376         // time the prerender was started (so as to not artificially advantage | 479   // comparing URLs. This may not always work: the URL may occur in two | 
| 377         // the PLT computation). | 480   // tabs, and we pick the wrong one, or the tab we should have picked | 
| 378         base::Time simulated_new_start_time = | 481   // may have navigated elsewhere. Hopefully, this doesn't happen too often, | 
| 379             current_time - base::TimeDelta::FromSeconds(10); | 482   // so we ignore these cases for now. | 
| 380         if (simulated_new_start_time > current_prerender_->start_time) | 483   // TODO(tburkard): Reconsider this, potentially measure it, and fix this | 
| 381           current_prerender_->start_time = simulated_new_start_time; | 484   // in the future. | 
| 382       } else { | 485   for (TabContentsIterator it; !it.done(); it.Next()) { | 
| 383         current_prerender_.reset( | 486     if (it->GetURL() == info->source_url_.url) { | 
| 384             new PrerenderData(url_id, url, priority, current_time)); | 487       source_web_contents = *it; | 
| 385       } | 488       break; | 
| 386       current_prerender_->actual_start_time = current_time; |  | 
| 387     } else { |  | 
| 388       RecordEvent(EVENT_ADD_VISIT_NOT_ROOTPAGE); |  | 
| 389     } | 489     } | 
| 390   } | 490   } | 
|  | 491 #endif | 
| 391 | 492 | 
|  | 493   if (!source_web_contents) { | 
|  | 494     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_NO_SOURCE_WEBCONTENTS_FOUND); | 
|  | 495     return; | 
|  | 496   } | 
|  | 497 | 
|  | 498   scoped_refptr<SessionStorageNamespace> session_storage_namespace = | 
|  | 499       source_web_contents->GetController().GetDefaultSessionStorageNamespace(); | 
|  | 500 | 
|  | 501   gfx::Rect container_bounds; | 
|  | 502   source_web_contents->GetView()->GetContainerBounds(&container_bounds); | 
|  | 503   scoped_ptr<gfx::Size> size(new gfx::Size(container_bounds.size())); | 
|  | 504 | 
|  | 505   scoped_refptr<LoggedInPredictorTable> logged_in_table = | 
|  | 506       prerender_manager_->logged_in_predictor_table(); | 
|  | 507 | 
|  | 508   if (!logged_in_table.get()) { | 
|  | 509     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_NO_LOGGED_IN_TABLE_FOUND); | 
|  | 510     return; | 
|  | 511   } | 
|  | 512 | 
|  | 513   RecordEvent(EVENT_PRERENDER_URL_LOOKUP_ISSUING_LOGGED_IN_LOOKUP); | 
|  | 514 | 
|  | 515   LocalPredictorURLLookupInfo* info_ptr = info.get(); | 
|  | 516   BrowserThread::PostTaskAndReply( | 
|  | 517       BrowserThread::DB, FROM_HERE, | 
|  | 518       base::Bind(&LookupLoggedInStatesOnDBThread, | 
|  | 519                  logged_in_table, | 
|  | 520                  info_ptr), | 
|  | 521       base::Bind(&PrerenderLocalPredictor::ContinuePrerenderCheck, | 
|  | 522                  weak_factory_.GetWeakPtr(), | 
|  | 523                  session_storage_namespace, | 
|  | 524                  base::Passed(&size), | 
|  | 525                  base::Passed(&info))); | 
|  | 526 } | 
|  | 527 | 
|  | 528 void PrerenderLocalPredictor::LogCandidateURLStats(const GURL& url) const { | 
| 392   if (url_whitelist_.count(GetInt64URLHashForURL(url)) > 0) { | 529   if (url_whitelist_.count(GetInt64URLHashForURL(url)) > 0) { | 
| 393     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST); | 530     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST); | 
| 394     if (IsRootPageURL(url)) | 531     if (IsRootPageURL(url)) | 
| 395       RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST_ROOT_PAGE); | 532       RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ON_WHITELIST_ROOT_PAGE); | 
| 396   } | 533   } | 
| 397   if (IsRootPageURL(url)) | 534   if (IsRootPageURL(url)) | 
| 398     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE); | 535     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE); | 
| 399   if (IsExtendedRootURL(url)) | 536   if (IsExtendedRootURL(url)) | 
| 400     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_EXTENDED_ROOT_PAGE); | 537     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_EXTENDED_ROOT_PAGE); | 
| 401   if (IsRootPageURL(url) && url.SchemeIs("http")) | 538   if (IsRootPageURL(url) && url.SchemeIs("http")) | 
| 402     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE_HTTP); | 539     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_ROOT_PAGE_HTTP); | 
| 403   if (url.SchemeIs("http")) | 540   if (url.SchemeIs("http")) | 
| 404     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_IS_HTTP); | 541     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_IS_HTTP); | 
| 405   if (url.has_query()) | 542   if (url.has_query()) | 
| 406     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_HAS_QUERY_STRING); | 543     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_HAS_QUERY_STRING); | 
| 407   if (StrCaseStr(url.spec().c_str(), "logout") || | 544   if (IsLogOutURL(url)) | 
| 408       StrCaseStr(url.spec().c_str(), "signout")) |  | 
| 409     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGOUT); | 545     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGOUT); | 
| 410   if (StrCaseStr(url.spec().c_str(), "login") || | 546   if (IsLogInURL(url)) | 
| 411       StrCaseStr(url.spec().c_str(), "signin")) |  | 
| 412     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGIN); | 547     RecordEvent(EVENT_PRERENDER_URL_LOOKUP_RESULT_CONTAINS_LOGIN); | 
| 413 } | 548 } | 
| 414 | 549 | 
| 415 void PrerenderLocalPredictor::OnGetInitialVisitHistory( | 550 void PrerenderLocalPredictor::OnGetInitialVisitHistory( | 
| 416     scoped_ptr<std::vector<history::BriefVisitInfo> > visit_history) { | 551     scoped_ptr<vector<history::BriefVisitInfo> > visit_history) { | 
| 417   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 552   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
| 418   DCHECK(!visit_history_.get()); | 553   DCHECK(!visit_history_.get()); | 
| 419   RecordEvent(EVENT_INIT_SUCCEEDED); | 554   RecordEvent(EVENT_INIT_SUCCEEDED); | 
| 420   // Since the visit history has descending timestamps, we must reverse it. | 555   // Since the visit history has descending timestamps, we must reverse it. | 
| 421   visit_history_.reset(new std::vector<history::BriefVisitInfo>( | 556   visit_history_.reset(new vector<history::BriefVisitInfo>( | 
| 422       visit_history->rbegin(), visit_history->rend())); | 557       visit_history->rbegin(), visit_history->rend())); | 
| 423 } | 558 } | 
| 424 | 559 | 
| 425 HistoryService* PrerenderLocalPredictor::GetHistoryIfExists() const { | 560 HistoryService* PrerenderLocalPredictor::GetHistoryIfExists() const { | 
| 426   Profile* profile = prerender_manager_->profile(); | 561   Profile* profile = prerender_manager_->profile(); | 
| 427   if (!profile) | 562   if (!profile) | 
| 428     return NULL; | 563     return NULL; | 
| 429   return HistoryServiceFactory::GetForProfileWithoutCreating(profile); | 564   return HistoryServiceFactory::GetForProfileWithoutCreating(profile); | 
| 430 } | 565 } | 
| 431 | 566 | 
| 432 void PrerenderLocalPredictor::Init() { | 567 void PrerenderLocalPredictor::Init() { | 
| 433   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 568   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
| 434   RecordEvent(EVENT_INIT_STARTED); | 569   RecordEvent(EVENT_INIT_STARTED); | 
| 435   HistoryService* history = GetHistoryIfExists(); | 570   HistoryService* history = GetHistoryIfExists(); | 
| 436   if (history) { | 571   if (history) { | 
| 437     CHECK(!is_visit_database_observer_); | 572     CHECK(!is_visit_database_observer_); | 
| 438     history->ScheduleDBTask( | 573     history->ScheduleDBTask( | 
| 439         new GetVisitHistoryTask(this, kMaxVisitHistory), | 574         new GetVisitHistoryTask(this, kMaxVisitHistory), | 
| 440         &history_db_consumer_); | 575         &history_db_consumer_); | 
| 441     history->AddVisitDatabaseObserver(this); | 576     history->AddVisitDatabaseObserver(this); | 
| 442     is_visit_database_observer_ = true; | 577     is_visit_database_observer_ = true; | 
| 443   } else { | 578   } else { | 
| 444     RecordEvent(EVENT_INIT_FAILED_NO_HISTORY); | 579     RecordEvent(EVENT_INIT_FAILED_NO_HISTORY); | 
| 445   } | 580   } | 
| 446 } | 581 } | 
| 447 | 582 | 
| 448 void PrerenderLocalPredictor::OnPLTEventForURL(const GURL& url, | 583 void PrerenderLocalPredictor::OnPLTEventForURL(const GURL& url, | 
| 449                                                base::TimeDelta page_load_time) { | 584                                                base::TimeDelta page_load_time) { | 
| 450   scoped_ptr<PrerenderData> prerender; | 585   scoped_ptr<PrerenderProperties> prerender; | 
| 451   if (DoesPrerenderMatchPLTRecord(last_swapped_in_prerender_.get(), | 586   if (DoesPrerenderMatchPLTRecord(last_swapped_in_prerender_.get(), | 
| 452                                   url, page_load_time)) { | 587                                   url, page_load_time)) { | 
| 453     prerender.reset(last_swapped_in_prerender_.release()); | 588     prerender.reset(last_swapped_in_prerender_.release()); | 
| 454   } | 589   } | 
| 455   if (DoesPrerenderMatchPLTRecord(current_prerender_.get(), | 590   if (DoesPrerenderMatchPLTRecord(current_prerender_.get(), | 
| 456                                   url, page_load_time)) { | 591                                   url, page_load_time)) { | 
| 457     prerender.reset(current_prerender_.release()); | 592     prerender.reset(current_prerender_.release()); | 
| 458   } | 593   } | 
| 459   if (!prerender.get()) | 594   if (!prerender.get()) | 
| 460     return; | 595     return; | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 473       UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.SimulatedLocalBrowsingPLT", | 608       UMA_HISTOGRAM_CUSTOM_TIMES("Prerender.SimulatedLocalBrowsingPLT", | 
| 474                                  new_plt, | 609                                  new_plt, | 
| 475                                  base::TimeDelta::FromMilliseconds(10), | 610                                  base::TimeDelta::FromMilliseconds(10), | 
| 476                                  base::TimeDelta::FromSeconds(60), | 611                                  base::TimeDelta::FromSeconds(60), | 
| 477                                  100); | 612                                  100); | 
| 478     } | 613     } | 
| 479   } | 614   } | 
| 480 } | 615 } | 
| 481 | 616 | 
| 482 bool PrerenderLocalPredictor::IsPrerenderStillValid( | 617 bool PrerenderLocalPredictor::IsPrerenderStillValid( | 
| 483     PrerenderLocalPredictor::PrerenderData* prerender) const { | 618     PrerenderLocalPredictor::PrerenderProperties* prerender) const { | 
| 484   return (prerender && | 619   return (prerender && | 
| 485           (prerender->start_time + | 620           (prerender->start_time + | 
| 486            base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs)) | 621            base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs)) | 
| 487           > GetCurrentTime()); | 622           > GetCurrentTime()); | 
| 488 } | 623 } | 
| 489 | 624 | 
| 490 void PrerenderLocalPredictor::RecordEvent( | 625 void PrerenderLocalPredictor::RecordEvent( | 
| 491     PrerenderLocalPredictor::Event event) const { | 626     PrerenderLocalPredictor::Event event) const { | 
| 492   UMA_HISTOGRAM_ENUMERATION("Prerender.LocalPredictorEvent", | 627   UMA_HISTOGRAM_ENUMERATION("Prerender.LocalPredictorEvent", | 
| 493       event, PrerenderLocalPredictor::EVENT_MAX_VALUE); | 628       event, PrerenderLocalPredictor::EVENT_MAX_VALUE); | 
| 494 } | 629 } | 
| 495 | 630 | 
| 496 bool PrerenderLocalPredictor::DoesPrerenderMatchPLTRecord( | 631 bool PrerenderLocalPredictor::DoesPrerenderMatchPLTRecord( | 
| 497     PrerenderData* prerender, const GURL& url, base::TimeDelta plt) const { | 632     PrerenderProperties* prerender, | 
|  | 633     const GURL& url, | 
|  | 634     base::TimeDelta plt) const { | 
| 498   if (prerender && prerender->start_time < GetCurrentTime() - plt) { | 635   if (prerender && prerender->start_time < GetCurrentTime() - plt) { | 
| 499     if (prerender->url.is_empty()) | 636     if (prerender->url.is_empty()) | 
| 500       RecordEvent(EVENT_ERROR_NO_PRERENDER_URL_FOR_PLT); | 637       RecordEvent(EVENT_ERROR_NO_PRERENDER_URL_FOR_PLT); | 
| 501     return (prerender->url == url); | 638     return (prerender->url == url); | 
| 502   } else { | 639   } else { | 
| 503     return false; | 640     return false; | 
| 504   } | 641   } | 
| 505 } | 642 } | 
| 506 | 643 | 
| 507 bool PrerenderLocalPredictor::ShouldReplaceCurrentPrerender( | 644 bool PrerenderLocalPredictor::ShouldReplaceCurrentPrerender( | 
| 508     double priority) const { | 645     double priority) const { | 
| 509   base::TimeDelta max_age = | 646   return (!prerender_handle_.get() || | 
| 510       base::TimeDelta::FromMilliseconds(kMaxLocalPredictionTimeMs); | 647           !prerender_handle_->IsPrerendering() || | 
| 511   return (!current_prerender_.get()) || | 648           current_prerender_priority_ < priority); | 
| 512     current_prerender_->priority < priority || | 649 } | 
| 513     current_prerender_->start_time < GetCurrentTime() - max_age; | 650 | 
|  | 651 void PrerenderLocalPredictor::ContinuePrerenderCheck( | 
|  | 652     scoped_refptr<SessionStorageNamespace> session_storage_namespace, | 
|  | 653     scoped_ptr<gfx::Size> size, | 
|  | 654     scoped_ptr<LocalPredictorURLLookupInfo> info) { | 
|  | 655   RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_STARTED); | 
|  | 656   scoped_ptr<LocalPredictorURLInfo> url_info; | 
|  | 657   for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) { | 
|  | 658     url_info.reset(new LocalPredictorURLInfo(info->candidate_urls_[i])); | 
|  | 659 | 
|  | 660     // We need to check whether we can issue a prerender for this URL. | 
|  | 661     // We test a set of conditions. Each condition can either rule out | 
|  | 662     // a prerender (in which case we reset url_info, so that it will not | 
|  | 663     // be prerendered, and we continue, which means try the next candidate | 
|  | 664     // URL), or it can be sufficient to issue the prerender without any | 
|  | 665     // further checks (in which case we just break). | 
|  | 666     // The order of the checks is critical, because it prescribes the logic | 
|  | 667     // we use here to decide what to prerender. | 
|  | 668     if (!url_info->url_lookup_success) { | 
|  | 669       RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_NO_URL); | 
|  | 670       url_info.reset(NULL); | 
|  | 671       continue; | 
|  | 672     } | 
|  | 673     if (!ShouldReplaceCurrentPrerender(url_info->priority)) { | 
|  | 674       RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_PRIORITY_TOO_LOW); | 
|  | 675       url_info.reset(NULL); | 
|  | 676       continue; | 
|  | 677     } | 
|  | 678     if (URLsIdenticalIgnoringFragments(info->source_url_.url, | 
|  | 679                                        url_info->url)) { | 
|  | 680       RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_URLS_IDENTICAL_BUT_FRAGMENT); | 
|  | 681       url_info.reset(NULL); | 
|  | 682       continue; | 
|  | 683     } | 
|  | 684     if (url_info->url.SchemeIs("https")) { | 
|  | 685       RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_HTTPS); | 
|  | 686       url_info.reset(NULL); | 
|  | 687       continue; | 
|  | 688     } | 
|  | 689     if (IsRootPageURL(url_info->url)) { | 
|  | 690       // For root pages, we assume that they are reasonably safe, and we | 
|  | 691       // will just prerender them without any additional checks. | 
|  | 692       RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ROOT_PAGE); | 
|  | 693       break; | 
|  | 694     } | 
|  | 695     if (IsLogOutURL(url_info->url)) { | 
|  | 696       RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_LOGOUT_URL); | 
|  | 697       url_info.reset(NULL); | 
|  | 698       continue; | 
|  | 699     } | 
|  | 700     if (IsLogInURL(url_info->url)) { | 
|  | 701       RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_LOGIN_URL); | 
|  | 702       url_info.reset(NULL); | 
|  | 703       continue; | 
|  | 704     } | 
|  | 705     if (!url_info->logged_in && url_info->logged_in_lookup_ok) { | 
|  | 706       RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_NOT_LOGGED_IN); | 
|  | 707       break; | 
|  | 708     } | 
|  | 709     RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_NOT_PRERENDERING); | 
|  | 710     url_info.reset(NULL); | 
|  | 711   } | 
|  | 712   if (!url_info.get()) | 
|  | 713     return; | 
|  | 714   RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ISSUING_PRERENDER); | 
|  | 715   IssuePrerender(session_storage_namespace, size.Pass(), | 
|  | 716                  url_info.Pass()); | 
|  | 717 } | 
|  | 718 | 
|  | 719 void PrerenderLocalPredictor::IssuePrerender( | 
|  | 720     scoped_refptr<SessionStorageNamespace> session_storage_namespace, | 
|  | 721     scoped_ptr<gfx::Size> size, | 
|  | 722     scoped_ptr<LocalPredictorURLInfo> info) { | 
|  | 723   URLID url_id = info->id; | 
|  | 724   const GURL& url = info->url; | 
|  | 725   double priority = info->priority; | 
|  | 726   base::Time current_time = GetCurrentTime(); | 
|  | 727   RecordEvent(EVENT_ISSUING_PRERENDER); | 
|  | 728 | 
|  | 729   current_prerender_priority_ = priority; | 
|  | 730   scoped_ptr<prerender::PrerenderHandle> old_prerender_handle( | 
|  | 731       prerender_handle_.release()); | 
|  | 732   prerender_handle_.reset(prerender_manager_->AddPrerenderFromLocalPredictor( | 
|  | 733       url, session_storage_namespace.get(), *size)); | 
|  | 734   if (old_prerender_handle) | 
|  | 735     old_prerender_handle->OnCancel(); | 
|  | 736 | 
|  | 737   RecordEvent(EVENT_ADD_VISIT_PRERENDERING); | 
|  | 738   if (current_prerender_.get() && current_prerender_->url_id == url_id) { | 
|  | 739     RecordEvent(EVENT_ADD_VISIT_PRERENDERING_EXTENDED); | 
|  | 740     if (priority > current_prerender_->priority) | 
|  | 741       current_prerender_->priority = priority; | 
|  | 742     // If the prerender already existed, we want to extend it.  However, | 
|  | 743     // we do not want to set its start_time to the current time to | 
|  | 744     // disadvantage PLT computations when the prerender is swapped in. | 
|  | 745     // So we set the new start time to current_time - 10s (since the vast | 
|  | 746     // majority of PLTs are < 10s), provided that is not before the actual | 
|  | 747     // time the prerender was started (so as to not artificially advantage | 
|  | 748     // the PLT computation). | 
|  | 749     base::Time simulated_new_start_time = | 
|  | 750         current_time - base::TimeDelta::FromSeconds(10); | 
|  | 751     if (simulated_new_start_time > current_prerender_->start_time) | 
|  | 752       current_prerender_->start_time = simulated_new_start_time; | 
|  | 753   } else { | 
|  | 754     current_prerender_.reset( | 
|  | 755         new PrerenderProperties(url_id, url, priority, current_time)); | 
|  | 756   } | 
|  | 757   current_prerender_->actual_start_time = current_time; | 
| 514 } | 758 } | 
| 515 | 759 | 
| 516 }  // namespace prerender | 760 }  // namespace prerender | 
| OLD | NEW | 
|---|