| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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_manager.h" | 5 #include "chrome/browser/prerender/prerender_manager.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/metrics/field_trial.h" | 11 #include "base/metrics/field_trial.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/time.h" | 13 #include "base/time.h" |
| 14 #include "base/values.h" | 14 #include "base/values.h" |
| 15 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
| 16 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
| 17 #include "chrome/browser/favicon/favicon_tab_helper.h" | 17 #include "chrome/browser/favicon/favicon_tab_helper.h" |
| 18 #include "chrome/browser/prerender/prerender_contents.h" | 18 #include "chrome/browser/prerender/prerender_contents.h" |
| 19 #include "chrome/browser/prerender/prerender_final_status.h" | 19 #include "chrome/browser/prerender/prerender_final_status.h" |
| 20 #include "chrome/browser/prerender/prerender_history.h" | 20 #include "chrome/browser/prerender/prerender_history.h" |
| 21 #include "chrome/browser/prerender/prerender_observer.h" | 21 #include "chrome/browser/prerender/prerender_observer.h" |
| 22 #include "chrome/browser/prerender/prerender_tracker.h" | 22 #include "chrome/browser/prerender/prerender_tracker.h" |
| 23 #include "chrome/browser/prerender/prerender_util.h" |
| 23 #include "chrome/browser/profiles/profile.h" | 24 #include "chrome/browser/profiles/profile.h" |
| 24 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 25 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 25 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper_delegate.h" | 26 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper_delegate.h" |
| 26 #include "chrome/common/chrome_switches.h" | 27 #include "chrome/common/chrome_switches.h" |
| 27 #include "chrome/common/render_messages.h" | 28 #include "chrome/common/render_messages.h" |
| 28 #include "content/browser/browser_thread.h" | 29 #include "content/browser/browser_thread.h" |
| 29 #include "content/browser/renderer_host/render_process_host.h" | 30 #include "content/browser/renderer_host/render_process_host.h" |
| 30 #include "content/browser/renderer_host/render_view_host.h" | 31 #include "content/browser/renderer_host/render_view_host.h" |
| 31 #include "content/browser/renderer_host/resource_dispatcher_host.h" | 32 #include "content/browser/renderer_host/resource_dispatcher_host.h" |
| 32 #include "content/browser/tab_contents/render_view_host_manager.h" | 33 #include "content/browser/tab_contents/render_view_host_manager.h" |
| 33 #include "content/browser/tab_contents/tab_contents.h" | 34 #include "content/browser/tab_contents/tab_contents.h" |
| 34 #include "content/browser/tab_contents/tab_contents_delegate.h" | 35 #include "content/browser/tab_contents/tab_contents_delegate.h" |
| 35 #include "content/common/notification_service.h" | 36 #include "content/common/notification_service.h" |
| 36 #include "googleurl/src/url_canon.h" | |
| 37 #include "googleurl/src/url_parse.h" | |
| 38 #include "googleurl/src/url_util.h" | |
| 39 | 37 |
| 40 namespace prerender { | 38 namespace prerender { |
| 41 | 39 |
| 42 namespace { | 40 namespace { |
| 43 | 41 |
| 44 // Time window for which we will record windowed PLT's from the last | 42 // Time window for which we will record windowed PLT's from the last |
| 45 // observed link rel=prefetch tag. | 43 // observed link rel=prefetch tag. |
| 46 const int kWindowDurationSeconds = 30; | 44 const int kWindowDurationSeconds = 30; |
| 47 | 45 |
| 48 // Time interval at which periodic cleanups are performed. | 46 // Time interval at which periodic cleanups are performed. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 61 "OPTIONS", | 59 "OPTIONS", |
| 62 "POST", | 60 "POST", |
| 63 "TRACE", | 61 "TRACE", |
| 64 }; | 62 }; |
| 65 | 63 |
| 66 // Length of prerender history, for display in chrome://net-internals | 64 // Length of prerender history, for display in chrome://net-internals |
| 67 const int kHistoryLength = 100; | 65 const int kHistoryLength = 100; |
| 68 | 66 |
| 69 } // namespace | 67 } // namespace |
| 70 | 68 |
| 69 // Helper macros for experiment-based and origin-based histogram reporting. |
| 70 #define PREFIXED_HISTOGRAM(histogram) \ |
| 71 PREFIXED_HISTOGRAM_INTERNAL(GetCurrentOrigin(), GetCurrentExperimentId(), \ |
| 72 IsOriginExperimentWash(), histogram) |
| 73 |
| 74 #define PREFIXED_HISTOGRAM_PRERENDER_MANAGER(pm, histogram) \ |
| 75 PREFIXED_HISTOGRAM_INTERNAL(pm->GetCurrentOrigin(), \ |
| 76 pm->GetCurrentExperimentId(), \ |
| 77 pm->IsOriginExperimentWash(), histogram) |
| 78 |
| 79 #define PREFIXED_HISTOGRAM_ORIGIN_EXPERIMENT(origin, experiment, histogram) \ |
| 80 PREFIXED_HISTOGRAM_INTERNAL(origin, experiment, false, histogram) |
| 81 |
| 82 #define PREFIXED_HISTOGRAM_INTERNAL(origin, experiment, wash, histogram) { \ |
| 83 static uint8 recording_experiment = kNoExperiment; \ |
| 84 if (recording_experiment == kNoExperiment && experiment != kNoExperiment) \ |
| 85 recording_experiment = experiment; \ |
| 86 if (wash) { \ |
| 87 histogram; \ |
| 88 } else if (experiment != kNoExperiment && \ |
| 89 (origin != ORIGIN_LINK_REL_PRERENDER || \ |
| 90 experiment != recording_experiment)) { \ |
| 91 } else if (experiment != kNoExperiment) { \ |
| 92 histogram; \ |
| 93 } else if (origin == ORIGIN_OMNIBOX) { \ |
| 94 histogram; \ |
| 95 } else { \ |
| 96 histogram; \ |
| 97 } \ |
| 98 } |
| 99 |
| 71 class PrerenderManager::OnCloseTabContentsDeleter : public TabContentsDelegate { | 100 class PrerenderManager::OnCloseTabContentsDeleter : public TabContentsDelegate { |
| 72 public: | 101 public: |
| 73 OnCloseTabContentsDeleter(PrerenderManager* manager, | 102 OnCloseTabContentsDeleter(PrerenderManager* manager, |
| 74 TabContentsWrapper* tab) | 103 TabContentsWrapper* tab) |
| 75 : manager_(manager), | 104 : manager_(manager), |
| 76 tab_(tab) { | 105 tab_(tab) { |
| 77 tab_->tab_contents()->set_delegate(this); | 106 tab_->tab_contents()->set_delegate(this); |
| 78 } | 107 } |
| 79 | 108 |
| 80 virtual void CloseContents(TabContents* source) OVERRIDE { | 109 virtual void CloseContents(TabContents* source) OVERRIDE { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 GetMode() == PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP || | 146 GetMode() == PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP || |
| 118 GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP; | 147 GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP; |
| 119 } | 148 } |
| 120 | 149 |
| 121 // static | 150 // static |
| 122 bool PrerenderManager::IsControlGroup() { | 151 bool PrerenderManager::IsControlGroup() { |
| 123 return GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP; | 152 return GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP; |
| 124 } | 153 } |
| 125 | 154 |
| 126 // static | 155 // static |
| 127 bool PrerenderManager::MaybeGetQueryStringBasedAliasURL( | |
| 128 const GURL& url, GURL* alias_url) { | |
| 129 DCHECK(alias_url); | |
| 130 url_parse::Parsed parsed; | |
| 131 url_parse::ParseStandardURL(url.spec().c_str(), url.spec().length(), | |
| 132 &parsed); | |
| 133 url_parse::Component query = parsed.query; | |
| 134 url_parse::Component key, value; | |
| 135 while (url_parse::ExtractQueryKeyValue(url.spec().c_str(), &query, &key, | |
| 136 &value)) { | |
| 137 if (key.len != 3 || strncmp(url.spec().c_str() + key.begin, "url", key.len)) | |
| 138 continue; | |
| 139 // We found a url= query string component. | |
| 140 if (value.len < 1) | |
| 141 continue; | |
| 142 url_canon::RawCanonOutputW<1024> decoded_url; | |
| 143 url_util::DecodeURLEscapeSequences(url.spec().c_str() + value.begin, | |
| 144 value.len, &decoded_url); | |
| 145 GURL new_url(string16(decoded_url.data(), decoded_url.length())); | |
| 146 if (!new_url.is_empty() && new_url.is_valid()) { | |
| 147 *alias_url = new_url; | |
| 148 return true; | |
| 149 } | |
| 150 return false; | |
| 151 } | |
| 152 return false; | |
| 153 } | |
| 154 | |
| 155 // static | |
| 156 bool PrerenderManager::IsValidHttpMethod(const std::string& method) { | 156 bool PrerenderManager::IsValidHttpMethod(const std::string& method) { |
| 157 // method has been canonicalized to upper case at this point so we can just | 157 // method has been canonicalized to upper case at this point so we can just |
| 158 // compare them. | 158 // compare them. |
| 159 DCHECK_EQ(method, StringToUpperASCII(method)); | 159 DCHECK_EQ(method, StringToUpperASCII(method)); |
| 160 for (size_t i = 0; i < arraysize(kValidHttpMethods); ++i) { | 160 for (size_t i = 0; i < arraysize(kValidHttpMethods); ++i) { |
| 161 if (method.compare(kValidHttpMethods[i]) == 0) | 161 if (method.compare(kValidHttpMethods[i]) == 0) |
| 162 return true; | 162 return true; |
| 163 } | 163 } |
| 164 | 164 |
| 165 return false; | 165 return false; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 193 GURL referrer_; | 193 GURL referrer_; |
| 194 Origin origin_; | 194 Origin origin_; |
| 195 }; | 195 }; |
| 196 | 196 |
| 197 PrerenderManager::PrerenderManager(Profile* profile, | 197 PrerenderManager::PrerenderManager(Profile* profile, |
| 198 PrerenderTracker* prerender_tracker) | 198 PrerenderTracker* prerender_tracker) |
| 199 : enabled_(true), | 199 : enabled_(true), |
| 200 profile_(profile), | 200 profile_(profile), |
| 201 prerender_tracker_(prerender_tracker), | 201 prerender_tracker_(prerender_tracker), |
| 202 prerender_contents_factory_(PrerenderContents::CreateFactory()), | 202 prerender_contents_factory_(PrerenderContents::CreateFactory()), |
| 203 last_experiment_id_(kNoExperiment), |
| 204 last_origin_(ORIGIN_LINK_REL_PRERENDER), |
| 205 origin_experiment_wash_(false), |
| 203 last_prerender_start_time_(GetCurrentTimeTicks() - | 206 last_prerender_start_time_(GetCurrentTimeTicks() - |
| 204 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)), | 207 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)), |
| 205 runnable_method_factory_(this), | 208 runnable_method_factory_(this), |
| 206 prerender_history_(new PrerenderHistory(kHistoryLength)) { | 209 prerender_history_(new PrerenderHistory(kHistoryLength)) { |
| 207 // There are some assumptions that the PrerenderManager is on the UI thread. | 210 // There are some assumptions that the PrerenderManager is on the UI thread. |
| 208 // Any other checks simply make sure that the PrerenderManager is accessed on | 211 // Any other checks simply make sure that the PrerenderManager is accessed on |
| 209 // the same thread that it was created on. | 212 // the same thread that it was created on. |
| 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 211 } | 214 } |
| 212 | 215 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 239 return AddPrerender(ORIGIN_OMNIBOX, std::make_pair(-1, -1), url, GURL()); | 242 return AddPrerender(ORIGIN_OMNIBOX, std::make_pair(-1, -1), url, GURL()); |
| 240 } | 243 } |
| 241 | 244 |
| 242 bool PrerenderManager::AddPrerender( | 245 bool PrerenderManager::AddPrerender( |
| 243 Origin origin, | 246 Origin origin, |
| 244 const std::pair<int, int>& child_route_id_pair, | 247 const std::pair<int, int>& child_route_id_pair, |
| 245 const GURL& url_arg, | 248 const GURL& url_arg, |
| 246 const GURL& referrer) { | 249 const GURL& referrer) { |
| 247 DCHECK(CalledOnValidThread()); | 250 DCHECK(CalledOnValidThread()); |
| 248 | 251 |
| 252 // Check if we are doing an experiment. |
| 253 uint8 experiment = GetQueryStringBasedExperiment(url_arg); |
| 254 |
| 255 // We need to update last_experiment_id_, last_origin_, and |
| 256 // origin_experiment_wash_. |
| 257 if (!WithinWindow()) { |
| 258 // If we are outside a window, this is a fresh start and we are fine, |
| 259 // and there is no mix. |
| 260 origin_experiment_wash_ = false; |
| 261 } else { |
| 262 // If we are inside the last window, there is a mish mash of origins |
| 263 // and experiments if either there was a mish mash before, or the current |
| 264 // experiment/origin does not match the previous one. |
| 265 if (experiment != last_experiment_id_ || origin != last_origin_) |
| 266 origin_experiment_wash_ = true; |
| 267 } |
| 268 |
| 269 last_origin_ = origin; |
| 270 last_experiment_id_ = experiment; |
| 271 |
| 249 // If we observe multiple tags within the 30 second window, we will still | 272 // If we observe multiple tags within the 30 second window, we will still |
| 250 // reset the window to begin at the most recent occurrence, so that we will | 273 // reset the window to begin at the most recent occurrence, so that we will |
| 251 // always be in a window in the 30 seconds from each occurrence. | 274 // always be in a window in the 30 seconds from each occurrence. |
| 252 last_prerender_seen_time_ = GetCurrentTimeTicks(); | 275 last_prerender_seen_time_ = GetCurrentTimeTicks(); |
| 253 | 276 |
| 254 // If the referring page is prerendering, defer the prerender. | 277 // If the referring page is prerendering, defer the prerender. |
| 255 if (FindPrerenderContentsForChildRouteIdPair(child_route_id_pair) != | 278 if (FindPrerenderContentsForChildRouteIdPair(child_route_id_pair) != |
| 256 prerender_list_.end()) { | 279 prerender_list_.end()) { |
| 257 AddPendingPrerender(origin, child_route_id_pair, url_arg, referrer); | 280 AddPendingPrerender(origin, child_route_id_pair, url_arg, referrer); |
| 258 return true; | 281 return true; |
| 259 } | 282 } |
| 260 | 283 |
| 261 DeleteOldEntries(); | 284 DeleteOldEntries(); |
| 262 DeletePendingDeleteEntries(); | 285 DeletePendingDeleteEntries(); |
| 263 | 286 |
| 264 GURL url = url_arg; | 287 GURL url = url_arg; |
| 265 GURL alias_url; | 288 GURL alias_url; |
| 266 if (IsControlGroup() && | 289 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url)) { |
| 267 PrerenderManager::MaybeGetQueryStringBasedAliasURL( | |
| 268 url, &alias_url)) { | |
| 269 url = alias_url; | 290 url = alias_url; |
| 270 } | 291 } |
| 271 | 292 |
| 272 if (FindEntry(url)) | 293 if (FindEntry(url)) |
| 273 return false; | 294 return false; |
| 274 | 295 |
| 275 // Do not prerender if there are too many render processes, and we would | 296 // Do not prerender if there are too many render processes, and we would |
| 276 // have to use an existing one. We do not want prerendering to happen in | 297 // have to use an existing one. We do not want prerendering to happen in |
| 277 // a shared process, so that we can always reliably lower the CPU | 298 // a shared process, so that we can always reliably lower the CPU |
| 278 // priority for prerendering. | 299 // priority for prerendering. |
| 279 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns | 300 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns |
| 280 // true, so that case needs to be explicitly checked for. | 301 // true, so that case needs to be explicitly checked for. |
| 281 // TODO(tburkard): Figure out how to cancel prerendering in the opposite | 302 // TODO(tburkard): Figure out how to cancel prerendering in the opposite |
| 282 // case, when a new tab is added to a process used for prerendering. | 303 // case, when a new tab is added to a process used for prerendering. |
| 283 if (RenderProcessHost::ShouldTryToUseExistingProcessHost() && | 304 if (RenderProcessHost::ShouldTryToUseExistingProcessHost() && |
| 284 !RenderProcessHost::run_renderer_in_process()) { | 305 !RenderProcessHost::run_renderer_in_process()) { |
| 285 RecordFinalStatus(origin, FINAL_STATUS_TOO_MANY_PROCESSES); | 306 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); |
| 286 return false; | 307 return false; |
| 287 } | 308 } |
| 288 | 309 |
| 289 // Check if enough time has passed since the last prerender. | 310 // Check if enough time has passed since the last prerender. |
| 290 if (!DoesRateLimitAllowPrerender()) { | 311 if (!DoesRateLimitAllowPrerender()) { |
| 291 // Cancel the prerender. We could add it to the pending prerender list but | 312 // Cancel the prerender. We could add it to the pending prerender list but |
| 292 // this doesn't make sense as the next prerender request will be triggered | 313 // this doesn't make sense as the next prerender request will be triggered |
| 293 // by a navigation and is unlikely to be the same site. | 314 // by a navigation and is unlikely to be the same site. |
| 294 RecordFinalStatus(origin, FINAL_STATUS_RATE_LIMIT_EXCEEDED); | 315 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); |
| 295 return false; | 316 return false; |
| 296 } | 317 } |
| 297 | 318 |
| 298 RenderViewHost* source_render_view_host = NULL; | 319 RenderViewHost* source_render_view_host = NULL; |
| 299 // This test should fail only during unit tests. | 320 // This test should fail only during unit tests. |
| 300 if (child_route_id_pair.first != -1) { | 321 if (child_route_id_pair.first != -1) { |
| 301 source_render_view_host = | 322 source_render_view_host = |
| 302 RenderViewHost::FromID(child_route_id_pair.first, | 323 RenderViewHost::FromID(child_route_id_pair.first, |
| 303 child_route_id_pair.second); | 324 child_route_id_pair.second); |
| 304 // Don't prerender page if parent RenderViewHost no longer exists, or it has | 325 // Don't prerender page if parent RenderViewHost no longer exists, or it has |
| 305 // no view. The latter should only happen when the RenderView has closed. | 326 // no view. The latter should only happen when the RenderView has closed. |
| 306 if (!source_render_view_host || !source_render_view_host->view()) { | 327 if (!source_render_view_host || !source_render_view_host->view()) { |
| 307 RecordFinalStatus(origin, FINAL_STATUS_SOURCE_RENDER_VIEW_CLOSED); | 328 RecordFinalStatus(origin, experiment, |
| 329 FINAL_STATUS_SOURCE_RENDER_VIEW_CLOSED); |
| 308 return false; | 330 return false; |
| 309 } | 331 } |
| 310 } | 332 } |
| 311 | 333 |
| 312 PrerenderContents* prerender_contents = | 334 PrerenderContents* prerender_contents = |
| 313 CreatePrerenderContents(url, referrer, origin); | 335 CreatePrerenderContents(url, referrer, origin, experiment); |
| 314 if (!prerender_contents || !prerender_contents->Init()) | 336 if (!prerender_contents || !prerender_contents->Init()) |
| 315 return false; | 337 return false; |
| 316 | 338 |
| 317 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? | 339 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? |
| 318 PrerenderContentsData data(prerender_contents, GetCurrentTime()); | 340 PrerenderContentsData data(prerender_contents, GetCurrentTime()); |
| 319 | 341 |
| 320 prerender_list_.push_back(data); | 342 prerender_list_.push_back(data); |
| 321 | 343 |
| 322 if (IsControlGroup()) { | 344 if (IsControlGroup()) { |
| 323 data.contents_->set_final_status(FINAL_STATUS_CONTROL_GROUP); | 345 data.contents_->set_final_status(FINAL_STATUS_CONTROL_GROUP); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 // Try to set the prerendered page as used, so any subsequent attempts to | 495 // Try to set the prerendered page as used, so any subsequent attempts to |
| 474 // cancel on other threads will fail. If this fails because the prerender | 496 // cancel on other threads will fail. If this fails because the prerender |
| 475 // was already cancelled, possibly on another thread, fail. | 497 // was already cancelled, possibly on another thread, fail. |
| 476 if (!prerender_tracker_->TryUse(child_id, route_id)) | 498 if (!prerender_tracker_->TryUse(child_id, route_id)) |
| 477 return false; | 499 return false; |
| 478 | 500 |
| 479 if (!prerender_contents->load_start_time().is_null()) | 501 if (!prerender_contents->load_start_time().is_null()) |
| 480 RecordTimeUntilUsed(GetCurrentTimeTicks() - | 502 RecordTimeUntilUsed(GetCurrentTimeTicks() - |
| 481 prerender_contents->load_start_time()); | 503 prerender_contents->load_start_time()); |
| 482 | 504 |
| 483 UMA_HISTOGRAM_COUNTS("Prerender.PrerendersPerSessionCount", | 505 PREFIXED_HISTOGRAM(UMA_HISTOGRAM_COUNTS( |
| 484 ++prerenders_per_session_count_); | 506 GetDefaultHistogramName("PrerendersPerSessionCount"), |
| 507 ++prerenders_per_session_count_)); |
| 485 prerender_contents->set_final_status(FINAL_STATUS_USED); | 508 prerender_contents->set_final_status(FINAL_STATUS_USED); |
| 486 | 509 |
| 487 RenderViewHost* render_view_host = | 510 RenderViewHost* render_view_host = |
| 488 prerender_contents->prerender_contents()->render_view_host(); | 511 prerender_contents->prerender_contents()->render_view_host(); |
| 489 DCHECK(render_view_host); | 512 DCHECK(render_view_host); |
| 490 render_view_host->Send( | 513 render_view_host->Send( |
| 491 new ViewMsg_SetIsPrerendering(render_view_host->routing_id(), false)); | 514 new ViewMsg_SetIsPrerendering(render_view_host->routing_id(), false)); |
| 492 | 515 |
| 493 TabContentsWrapper* new_tab_contents = | 516 TabContentsWrapper* new_tab_contents = |
| 494 prerender_contents->ReleasePrerenderContents(); | 517 prerender_contents->ReleasePrerenderContents(); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 584 | 607 |
| 585 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { | 608 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { |
| 586 DCHECK(CalledOnValidThread()); | 609 DCHECK(CalledOnValidThread()); |
| 587 base::Time now = GetCurrentTime(); | 610 base::Time now = GetCurrentTime(); |
| 588 return (now - start < config_.max_age); | 611 return (now - start < config_.max_age); |
| 589 } | 612 } |
| 590 | 613 |
| 591 PrerenderContents* PrerenderManager::CreatePrerenderContents( | 614 PrerenderContents* PrerenderManager::CreatePrerenderContents( |
| 592 const GURL& url, | 615 const GURL& url, |
| 593 const GURL& referrer, | 616 const GURL& referrer, |
| 594 Origin origin) { | 617 Origin origin, |
| 618 uint8 experiment_id) { |
| 595 DCHECK(CalledOnValidThread()); | 619 DCHECK(CalledOnValidThread()); |
| 596 return prerender_contents_factory_->CreatePrerenderContents( | 620 return prerender_contents_factory_->CreatePrerenderContents( |
| 597 this, prerender_tracker_, profile_, url, referrer, origin); | 621 this, prerender_tracker_, profile_, url, referrer, origin, experiment_id); |
| 598 } | 622 } |
| 599 | 623 |
| 600 bool PrerenderManager::IsPendingDelete(PrerenderContents* entry) const { | 624 bool PrerenderManager::IsPendingDelete(PrerenderContents* entry) const { |
| 601 DCHECK(CalledOnValidThread()); | 625 DCHECK(CalledOnValidThread()); |
| 602 for (std::list<PrerenderContents*>::const_iterator it = | 626 for (std::list<PrerenderContents*>::const_iterator it = |
| 603 pending_delete_list_.begin(); | 627 pending_delete_list_.begin(); |
| 604 it != pending_delete_list_.end(); | 628 it != pending_delete_list_.end(); |
| 605 ++it) { | 629 ++it) { |
| 606 if (*it == entry) | 630 if (*it == entry) |
| 607 return true; | 631 return true; |
| 608 } | 632 } |
| 609 | 633 |
| 610 return false; | 634 return false; |
| 611 } | 635 } |
| 612 | 636 |
| 613 void PrerenderManager::DeletePendingDeleteEntries() { | 637 void PrerenderManager::DeletePendingDeleteEntries() { |
| 614 while (!pending_delete_list_.empty()) { | 638 while (!pending_delete_list_.empty()) { |
| 615 PrerenderContents* contents = pending_delete_list_.front(); | 639 PrerenderContents* contents = pending_delete_list_.front(); |
| 616 pending_delete_list_.pop_front(); | 640 pending_delete_list_.pop_front(); |
| 617 AddToHistory(contents); | 641 AddToHistory(contents); |
| 618 delete contents; | 642 delete contents; |
| 619 } | 643 } |
| 620 } | 644 } |
| 621 | 645 |
| 622 // Helper macro for histograms. | 646 // Helper macro for histograms. |
| 623 #define RECORD_PLT(tag, perceived_page_load_time) { \ | 647 #define RECORD_PLT(tag, perceived_page_load_time) { \ |
| 648 PREFIXED_HISTOGRAM_PRERENDER_MANAGER(prerender_manager, \ |
| 624 UMA_HISTOGRAM_CUSTOM_TIMES( \ | 649 UMA_HISTOGRAM_CUSTOM_TIMES( \ |
| 625 base::FieldTrial::MakeName(std::string("Prerender.") + tag, \ | 650 base::FieldTrial::MakeName( \ |
| 626 "Prefetch"), \ | 651 prerender_manager->GetDefaultHistogramName(tag), "Prefetch"), \ |
| 627 perceived_page_load_time, \ | 652 perceived_page_load_time, \ |
| 628 base::TimeDelta::FromMilliseconds(10), \ | 653 base::TimeDelta::FromMilliseconds(10), \ |
| 629 base::TimeDelta::FromSeconds(60), \ | 654 base::TimeDelta::FromSeconds(60), \ |
| 630 100); \ | 655 100)); \ |
| 631 } | 656 } |
| 632 | 657 |
| 633 // static | 658 // static |
| 634 void PrerenderManager::RecordPerceivedPageLoadTime( | 659 void PrerenderManager::RecordPerceivedPageLoadTime( |
| 635 base::TimeDelta perceived_page_load_time, | 660 base::TimeDelta perceived_page_load_time, |
| 636 TabContents* tab_contents) { | 661 TabContents* tab_contents) { |
| 637 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 662 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 638 PrerenderManager* prerender_manager = | 663 PrerenderManager* prerender_manager = |
| 639 tab_contents->profile()->GetPrerenderManager(); | 664 tab_contents->profile()->GetPrerenderManager(); |
| 640 if (!prerender_manager) | 665 if (!prerender_manager) |
| 641 return; | 666 return; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 719 return false; | 744 return false; |
| 720 base::TimeDelta elapsed_time = | 745 base::TimeDelta elapsed_time = |
| 721 base::TimeTicks::Now() - last_prerender_seen_time_; | 746 base::TimeTicks::Now() - last_prerender_seen_time_; |
| 722 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowDurationSeconds); | 747 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowDurationSeconds); |
| 723 } | 748 } |
| 724 | 749 |
| 725 bool PrerenderManager::DoesRateLimitAllowPrerender() const { | 750 bool PrerenderManager::DoesRateLimitAllowPrerender() const { |
| 726 DCHECK(CalledOnValidThread()); | 751 DCHECK(CalledOnValidThread()); |
| 727 base::TimeDelta elapsed_time = | 752 base::TimeDelta elapsed_time = |
| 728 GetCurrentTimeTicks() - last_prerender_start_time_; | 753 GetCurrentTimeTicks() - last_prerender_start_time_; |
| 729 UMA_HISTOGRAM_TIMES("Prerender.TimeBetweenPrerenderRequests", | 754 PREFIXED_HISTOGRAM( |
| 730 elapsed_time); | 755 UMA_HISTOGRAM_TIMES( |
| 756 GetDefaultHistogramName("TimeBetweenPrerenderRequests"), |
| 757 elapsed_time)); |
| 731 if (!config_.rate_limit_enabled) | 758 if (!config_.rate_limit_enabled) |
| 732 return true; | 759 return true; |
| 733 return elapsed_time > | 760 return elapsed_time > |
| 734 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); | 761 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); |
| 735 } | 762 } |
| 736 | 763 |
| 737 void PrerenderManager::StartSchedulingPeriodicCleanups() { | 764 void PrerenderManager::StartSchedulingPeriodicCleanups() { |
| 738 DCHECK(CalledOnValidThread()); | 765 DCHECK(CalledOnValidThread()); |
| 739 if (repeating_timer_.IsRunning()) | 766 if (repeating_timer_.IsRunning()) |
| 740 return; | 767 return; |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 960 while (!prerender_list_.empty()) { | 987 while (!prerender_list_.empty()) { |
| 961 PrerenderContentsData data = prerender_list_.front(); | 988 PrerenderContentsData data = prerender_list_.front(); |
| 962 prerender_list_.pop_front(); | 989 prerender_list_.pop_front(); |
| 963 data.contents_->Destroy(final_status); | 990 data.contents_->Destroy(final_status); |
| 964 } | 991 } |
| 965 DeletePendingDeleteEntries(); | 992 DeletePendingDeleteEntries(); |
| 966 } | 993 } |
| 967 | 994 |
| 968 void PrerenderManager::RecordTimeUntilUsed(base::TimeDelta time_until_used) { | 995 void PrerenderManager::RecordTimeUntilUsed(base::TimeDelta time_until_used) { |
| 969 DCHECK(CalledOnValidThread()); | 996 DCHECK(CalledOnValidThread()); |
| 970 UMA_HISTOGRAM_CUSTOM_TIMES( | 997 PREFIXED_HISTOGRAM(UMA_HISTOGRAM_CUSTOM_TIMES( |
| 971 "Prerender.TimeUntilUsed", | 998 GetDefaultHistogramName("TimeUntilUsed"), |
| 972 time_until_used, | 999 time_until_used, |
| 973 base::TimeDelta::FromMilliseconds(10), | 1000 base::TimeDelta::FromMilliseconds(10), |
| 974 config_.max_age, | 1001 config_.max_age, |
| 975 50); | 1002 50)); |
| 1003 } |
| 1004 |
| 1005 void PrerenderManager::RecordFinalStatus(Origin origin, |
| 1006 uint8 experiment_id, |
| 1007 FinalStatus final_status) const { |
| 1008 DCHECK(final_status != FINAL_STATUS_MAX); |
| 1009 // FINAL_STATUS_CONTROL_GROUP indicates that the PrerenderContents |
| 1010 // was created only to measure "would-have-been-prerendered" for |
| 1011 // control group measurements. Don't pollute data with it. |
| 1012 if (PrerenderManager::IsControlGroup() || |
| 1013 final_status == FINAL_STATUS_CONTROL_GROUP) |
| 1014 return; |
| 1015 PREFIXED_HISTOGRAM_ORIGIN_EXPERIMENT(origin, experiment_id, |
| 1016 UMA_HISTOGRAM_ENUMERATION( |
| 1017 GetHistogramName(origin, experiment_id, "FinalStatus"), |
| 1018 final_status, |
| 1019 FINAL_STATUS_MAX)); |
| 1020 } |
| 1021 |
| 1022 std::string PrerenderManager::ComposeHistogramName( |
| 1023 const std::string& prefix_type, |
| 1024 const std::string& name) const { |
| 1025 if (prefix_type.empty()) |
| 1026 return std::string("Prerender.") + name; |
| 1027 return std::string("Prerender.") + prefix_type + std::string("_") + name; |
| 1028 } |
| 1029 |
| 1030 std::string PrerenderManager::GetHistogramName(Origin origin, |
| 1031 uint8 experiment_id, |
| 1032 const std::string& name) const { |
| 1033 switch (origin) { |
| 1034 case ORIGIN_OMNIBOX: |
| 1035 if (experiment_id != kNoExperiment) |
| 1036 return ComposeHistogramName("wash", name); |
| 1037 return ComposeHistogramName("omnibox", name); |
| 1038 case ORIGIN_LINK_REL_PRERENDER: |
| 1039 if (experiment_id == kNoExperiment) |
| 1040 return ComposeHistogramName("", name); |
| 1041 return ComposeHistogramName("exp" + std::string(1, experiment_id + '0'), |
| 1042 name); |
| 1043 default: |
| 1044 NOTREACHED(); |
| 1045 break; |
| 1046 }; |
| 1047 |
| 1048 // Dummy return value to make the compiler happy. |
| 1049 NOTREACHED(); |
| 1050 return ComposeHistogramName("wash", name); |
| 1051 } |
| 1052 |
| 1053 std::string PrerenderManager::GetDefaultHistogramName( |
| 1054 const std::string& name) const { |
| 1055 if (!WithinWindow()) |
| 1056 return ComposeHistogramName("", name); |
| 1057 if (origin_experiment_wash_) |
| 1058 return ComposeHistogramName("wash", name); |
| 1059 return GetHistogramName(last_origin_, last_experiment_id_, name); |
| 1060 } |
| 1061 |
| 1062 uint8 PrerenderManager::GetCurrentExperimentId() const { |
| 1063 if (!WithinWindow()) |
| 1064 return kNoExperiment; |
| 1065 return last_experiment_id_; |
| 1066 } |
| 1067 |
| 1068 Origin PrerenderManager::GetCurrentOrigin() const { |
| 1069 if (!WithinWindow()) |
| 1070 return ORIGIN_LINK_REL_PRERENDER; |
| 1071 return last_origin_; |
| 1072 } |
| 1073 |
| 1074 bool PrerenderManager::IsOriginExperimentWash() const { |
| 1075 if (!WithinWindow()) |
| 1076 return false; |
| 1077 return origin_experiment_wash_; |
| 976 } | 1078 } |
| 977 | 1079 |
| 978 } // namespace prerender | 1080 } // namespace prerender |
| OLD | NEW |