Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "components/page_load_metrics/browser/metrics_web_contents_observer.h" | 5 #include "components/page_load_metrics/browser/metrics_web_contents_observer.h" |
| 6 | 6 |
| 7 #include "base/location.h" | 7 #include "base/location.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/metrics/user_metrics.h" | 10 #include "base/metrics/user_metrics.h" |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 102 if (seconds < 32) | 102 if (seconds < 32) |
| 103 return 4; | 103 return 4; |
| 104 return 5; | 104 return 5; |
| 105 } | 105 } |
| 106 | 106 |
| 107 } // namespace | 107 } // namespace |
| 108 | 108 |
| 109 PageLoadTracker::PageLoadTracker( | 109 PageLoadTracker::PageLoadTracker( |
| 110 bool in_foreground, | 110 bool in_foreground, |
| 111 PageLoadMetricsEmbedderInterface* embedder_interface, | 111 PageLoadMetricsEmbedderInterface* embedder_interface, |
| 112 content::NavigationHandle* navigation_handle, | 112 content::NavigationHandle* navigation_handle) |
| 113 base::ObserverList<PageLoadMetricsObserver, true>* observers) | 113 : renderer_tracked_(false), |
| 114 : has_commit_(false), | 114 has_commit_(false), |
| 115 navigation_start_(navigation_handle->NavigationStart()), | 115 navigation_start_(navigation_handle->NavigationStart()), |
| 116 started_in_foreground_(in_foreground), | 116 started_in_foreground_(in_foreground), |
| 117 embedder_interface_(embedder_interface), | 117 embedder_interface_(embedder_interface) { |
| 118 observers_(observers) {} | 118 embedder_interface_->RegisterObservers(this); |
| 119 for (const auto& observer : observers_) { | |
| 120 observer->OnStart(navigation_handle); | |
| 121 } | |
| 122 } | |
| 119 | 123 |
| 120 PageLoadTracker::~PageLoadTracker() { | 124 PageLoadTracker::~PageLoadTracker() { |
| 121 if (has_commit_) { | 125 if (has_commit_) { |
| 122 RecordTimingHistograms(); | 126 RecordTimingHistograms(); |
| 123 RecordRappor(); | 127 RecordRappor(); |
| 124 } | 128 } |
| 129 PageLoadExtraInfo info = GetPageLoadMetricsInfo(); | |
| 130 for (const auto& observer : observers_) { | |
| 131 observer->OnComplete(timing_, info); | |
| 132 } | |
| 125 } | 133 } |
| 126 | 134 |
| 127 void PageLoadTracker::WebContentsHidden() { | 135 void PageLoadTracker::WebContentsHidden() { |
| 128 // Only log the first time we background in a given page load. | 136 // Only log the first time we background in a given page load. |
| 129 if (started_in_foreground_ && background_time_.is_null()) | 137 if (started_in_foreground_ && background_time_.is_null()) |
| 130 background_time_ = base::TimeTicks::Now(); | 138 background_time_ = base::TimeTicks::Now(); |
| 131 } | 139 } |
| 132 | 140 |
| 133 void PageLoadTracker::WebContentsShown() { | 141 void PageLoadTracker::WebContentsShown() { |
| 134 // Only log the first time we foreground in a given page load. | 142 // Only log the first time we foreground in a given page load. |
| 135 // Don't log foreground time if we started foregrounded. | 143 // Don't log foreground time if we started foregrounded. |
| 136 if (!started_in_foreground_ && foreground_time_.is_null()) | 144 if (!started_in_foreground_ && foreground_time_.is_null()) |
| 137 foreground_time_ = base::TimeTicks::Now(); | 145 foreground_time_ = base::TimeTicks::Now(); |
| 138 } | 146 } |
| 139 | 147 |
| 140 void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) { | 148 void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) { |
| 141 has_commit_ = true; | 149 has_commit_ = true; |
| 142 url_ = navigation_handle->GetURL(); | 150 url_ = navigation_handle->GetURL(); |
| 143 // We log the event that this load started. Because we don't know if a load is | 151 // We log the event that this load started. Because we don't know if a load is |
| 144 // relevant or if it will commit before now, we have to log this event at | 152 // relevant or if it will commit before now, we have to log this event at |
| 145 // commit time. | 153 // commit time. |
| 146 RecordCommittedEvent(COMMITTED_LOAD_STARTED, !started_in_foreground_); | 154 if (renderer_tracked()) |
| 155 RecordCommittedEvent(RELEVANT_LOAD_STARTED, !started_in_foreground_); | |
| 147 | 156 |
| 148 FOR_EACH_OBSERVER(PageLoadMetricsObserver, *observers_, | 157 for (const auto& observer : observers_) { |
| 149 OnCommit(navigation_handle)); | 158 observer->OnCommit(navigation_handle); |
| 159 } | |
| 150 } | 160 } |
| 151 | 161 |
| 152 void PageLoadTracker::Redirect(content::NavigationHandle* navigation_handle) { | 162 void PageLoadTracker::Redirect(content::NavigationHandle* navigation_handle) { |
| 153 FOR_EACH_OBSERVER(PageLoadMetricsObserver, *observers_, | 163 for (const auto& observer : observers_) { |
| 154 OnRedirect(navigation_handle)); | 164 observer->OnRedirect(navigation_handle); |
| 165 } | |
| 155 } | 166 } |
| 156 | 167 |
| 157 bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing) { | 168 bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing) { |
| 158 // Throw away IPCs that are not relevant to the current navigation. | 169 // Throw away IPCs that are not relevant to the current navigation. |
| 159 // Two timing structures cannot refer to the same navigation if they indicate | 170 // Two timing structures cannot refer to the same navigation if they indicate |
| 160 // that a navigation started at different times, so a new timing struct with a | 171 // that a navigation started at different times, so a new timing struct with a |
| 161 // different start time from an earlier struct is considered invalid. | 172 // different start time from an earlier struct is considered invalid. |
| 162 bool valid_timing_descendent = | 173 bool valid_timing_descendent = |
| 163 timing_.navigation_start.is_null() || | 174 timing_.navigation_start.is_null() || |
| 164 timing_.navigation_start == new_timing.navigation_start; | 175 timing_.navigation_start == new_timing.navigation_start; |
| 165 if (IsValidPageLoadTiming(new_timing) && valid_timing_descendent) { | 176 if (IsValidPageLoadTiming(new_timing) && valid_timing_descendent) { |
| 166 timing_ = new_timing; | 177 timing_ = new_timing; |
| 167 return true; | 178 return true; |
| 168 } | 179 } |
| 169 return false; | 180 return false; |
| 170 } | 181 } |
| 171 | 182 |
| 172 bool PageLoadTracker::HasBackgrounded() { | 183 bool PageLoadTracker::HasBackgrounded() { |
| 173 return !started_in_foreground_ || !background_time_.is_null(); | 184 return !started_in_foreground_ || !background_time_.is_null(); |
| 174 } | 185 } |
| 175 | 186 |
| 187 void PageLoadTracker::set_renderer_tracked(bool renderer_tracked) { | |
| 188 renderer_tracked_ = renderer_tracked; | |
| 189 } | |
| 190 | |
| 191 void PageLoadTracker::AddObserver( | |
| 192 scoped_ptr<PageLoadMetricsObserver> observer) { | |
| 193 observers_.push_back(std::move(observer)); | |
| 194 } | |
| 195 | |
| 176 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { | 196 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { |
| 177 base::TimeDelta first_background_time; | 197 base::TimeDelta first_background_time; |
| 178 base::TimeDelta first_foreground_time; | 198 base::TimeDelta first_foreground_time; |
| 179 if (!background_time_.is_null() && started_in_foreground_) | 199 if (!background_time_.is_null() && started_in_foreground_) |
| 180 first_background_time = background_time_ - navigation_start_; | 200 first_background_time = background_time_ - navigation_start_; |
| 181 if (!foreground_time_.is_null() && !started_in_foreground_) | 201 if (!foreground_time_.is_null() && !started_in_foreground_) |
| 182 first_foreground_time = foreground_time_ - navigation_start_; | 202 first_foreground_time = foreground_time_ - navigation_start_; |
| 183 return PageLoadExtraInfo(first_background_time, first_foreground_time, | 203 return PageLoadExtraInfo(first_background_time, first_foreground_time, |
| 184 started_in_foreground_); | 204 started_in_foreground_, has_commit_); |
| 185 } | 205 } |
| 186 | 206 |
| 187 const GURL& PageLoadTracker::GetCommittedURL() { | 207 const GURL& PageLoadTracker::committed_url() { |
| 188 DCHECK(has_commit_); | 208 DCHECK(has_commit_); |
| 189 return url_; | 209 return url_; |
| 190 } | 210 } |
| 191 | 211 |
| 192 // Blink calculates navigation start using TimeTicks, but converts to epoch time | 212 // Blink calculates navigation start using TimeTicks, but converts to epoch time |
| 193 // in its public API. Thus, to compare time values to navigation start, we | 213 // in its public API. Thus, to compare time values to navigation start, we |
| 194 // calculate the current time since the epoch using TimeTicks, and convert to | 214 // calculate the current time since the epoch using TimeTicks, and convert to |
| 195 // Time. This method is similar to how blink converts TimeTicks to epoch time. | 215 // Time. This method is similar to how blink converts TimeTicks to epoch time. |
| 196 // There may be slight inaccuracies due to inter-process timestamps, but | 216 // There may be slight inaccuracies due to inter-process timestamps, but |
| 197 // this solution is the best we have right now. | 217 // this solution is the best we have right now. |
| 198 // | 218 // |
| 199 // returns a TimeDelta which is | 219 // returns a TimeDelta which is |
| 200 // - Infinity if we were never backgrounded | 220 // - Infinity if we were never backgrounded |
| 201 // - null (TimeDelta()) if we started backgrounded | 221 // - null (TimeDelta()) if we started backgrounded |
| 202 // - elapsed time to first background if we started in the foreground and | 222 // - elapsed time to first background if we started in the foreground and |
| 203 // backgrounded. | 223 // backgrounded. |
| 204 base::TimeDelta PageLoadTracker::GetBackgroundDelta() { | 224 base::TimeDelta PageLoadTracker::GetBackgroundDelta() { |
| 205 if (started_in_foreground_) { | 225 if (started_in_foreground_) { |
| 206 return background_time_.is_null() ? base::TimeDelta::Max() | 226 return background_time_.is_null() ? base::TimeDelta::Max() |
| 207 : background_time_ - navigation_start_; | 227 : background_time_ - navigation_start_; |
| 208 } | 228 } |
| 209 return base::TimeDelta(); | 229 return base::TimeDelta(); |
| 210 } | 230 } |
| 211 | 231 |
| 212 void PageLoadTracker::RecordTimingHistograms() { | 232 void PageLoadTracker::RecordTimingHistograms() { |
| 213 DCHECK(has_commit_); | 233 DCHECK(has_commit_); |
| 234 if (!renderer_tracked()) | |
| 235 return; | |
| 236 | |
| 214 if (timing_.IsEmpty()) { | 237 if (timing_.IsEmpty()) { |
| 215 RecordInternalError(ERR_NO_IPCS_RECEIVED); | 238 RecordInternalError(ERR_NO_IPCS_RECEIVED); |
| 216 return; | 239 return; |
| 217 } | 240 } |
| 218 | 241 |
| 219 PageLoadExtraInfo info = GetPageLoadMetricsInfo(); | |
| 220 FOR_EACH_OBSERVER(PageLoadMetricsObserver, *observers_, | |
| 221 OnComplete(timing_, info)); | |
| 222 | |
| 223 base::TimeDelta background_delta = GetBackgroundDelta(); | 242 base::TimeDelta background_delta = GetBackgroundDelta(); |
| 224 | 243 |
| 225 if (!timing_.dom_content_loaded_event_start.is_zero()) { | 244 if (!timing_.dom_content_loaded_event_start.is_zero()) { |
| 226 if (timing_.dom_content_loaded_event_start < background_delta) { | 245 if (timing_.dom_content_loaded_event_start < background_delta) { |
| 227 PAGE_LOAD_HISTOGRAM(kHistogramDomContentLoaded, | 246 PAGE_LOAD_HISTOGRAM(kHistogramDomContentLoaded, |
| 228 timing_.dom_content_loaded_event_start); | 247 timing_.dom_content_loaded_event_start); |
| 229 } else { | 248 } else { |
| 230 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramDomContentLoaded, | 249 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramDomContentLoaded, |
| 231 timing_.dom_content_loaded_event_start); | 250 timing_.dom_content_loaded_event_start); |
| 232 } | 251 } |
| 233 } | 252 } |
| 234 if (!timing_.load_event_start.is_zero()) { | 253 if (!timing_.load_event_start.is_zero()) { |
| 235 if (timing_.load_event_start < background_delta) { | 254 if (timing_.load_event_start < background_delta) { |
| 236 PAGE_LOAD_HISTOGRAM(kHistogramLoad, timing_.load_event_start); | 255 PAGE_LOAD_HISTOGRAM(kHistogramLoad, timing_.load_event_start); |
| 237 } else { | 256 } else { |
| 238 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramLoad, timing_.load_event_start); | 257 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramLoad, timing_.load_event_start); |
| 239 } | 258 } |
| 240 } | 259 } |
| 241 if (timing_.first_layout.is_zero()) { | 260 if (timing_.first_layout.is_zero()) { |
| 242 RecordCommittedEvent(COMMITTED_LOAD_FAILED_BEFORE_FIRST_LAYOUT, | 261 RecordCommittedEvent(RELEVANT_LOAD_FAILED_BEFORE_FIRST_LAYOUT, |
| 243 HasBackgrounded()); | 262 HasBackgrounded()); |
| 244 } else { | 263 } else { |
| 245 if (timing_.first_layout < background_delta) { | 264 if (timing_.first_layout < background_delta) { |
| 246 PAGE_LOAD_HISTOGRAM(kHistogramFirstLayout, timing_.first_layout); | 265 PAGE_LOAD_HISTOGRAM(kHistogramFirstLayout, timing_.first_layout); |
| 247 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT, false); | 266 RecordCommittedEvent(RELEVANT_LOAD_SUCCESSFUL_FIRST_LAYOUT, false); |
| 248 } else { | 267 } else { |
| 249 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstLayout, | 268 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstLayout, |
| 250 timing_.first_layout); | 269 timing_.first_layout); |
| 251 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT, true); | 270 RecordCommittedEvent(RELEVANT_LOAD_SUCCESSFUL_FIRST_LAYOUT, true); |
| 252 } | 271 } |
| 253 } | 272 } |
| 254 if (!timing_.first_paint.is_zero()) { | 273 if (!timing_.first_paint.is_zero()) { |
| 255 if (timing_.first_paint < background_delta) { | 274 if (timing_.first_paint < background_delta) { |
| 256 PAGE_LOAD_HISTOGRAM(kHistogramFirstPaint, timing_.first_paint); | 275 PAGE_LOAD_HISTOGRAM(kHistogramFirstPaint, timing_.first_paint); |
| 257 } else { | 276 } else { |
| 258 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstPaint, timing_.first_paint); | 277 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstPaint, timing_.first_paint); |
| 259 } | 278 } |
| 260 } | 279 } |
| 261 if (!timing_.first_text_paint.is_zero()) { | 280 if (!timing_.first_text_paint.is_zero()) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 310 PROVISIONAL_LOAD_LAST_ENTRY); | 329 PROVISIONAL_LOAD_LAST_ENTRY); |
| 311 } else { | 330 } else { |
| 312 UMA_HISTOGRAM_ENUMERATION(kProvisionalEvents, event, | 331 UMA_HISTOGRAM_ENUMERATION(kProvisionalEvents, event, |
| 313 PROVISIONAL_LOAD_LAST_ENTRY); | 332 PROVISIONAL_LOAD_LAST_ENTRY); |
| 314 } | 333 } |
| 315 } | 334 } |
| 316 | 335 |
| 317 // RecordCommittedEvent needs a backgrounded input because we need to special | 336 // RecordCommittedEvent needs a backgrounded input because we need to special |
| 318 // case a few events that need either precise timing measurements, or different | 337 // case a few events that need either precise timing measurements, or different |
| 319 // logic than simply "Did I background before logging this event?" | 338 // logic than simply "Did I background before logging this event?" |
| 320 void PageLoadTracker::RecordCommittedEvent(CommittedLoadEvent event, | 339 void PageLoadTracker::RecordCommittedEvent(CommittedRelevantLoadEvent event, |
| 321 bool backgrounded) { | 340 bool backgrounded) { |
| 322 if (backgrounded) { | 341 if (backgrounded) { |
| 323 UMA_HISTOGRAM_ENUMERATION(kBackgroundCommittedEvents, event, | 342 UMA_HISTOGRAM_ENUMERATION(kBackgroundCommittedEvents, event, |
| 324 COMMITTED_LOAD_LAST_ENTRY); | 343 RELEVANT_LOAD_LAST_ENTRY); |
| 325 } else { | 344 } else { |
| 326 UMA_HISTOGRAM_ENUMERATION(kCommittedEvents, event, | 345 UMA_HISTOGRAM_ENUMERATION(kCommittedEvents, event, |
| 327 COMMITTED_LOAD_LAST_ENTRY); | 346 RELEVANT_LOAD_LAST_ENTRY); |
| 328 } | 347 } |
| 329 } | 348 } |
| 330 | 349 |
| 331 void PageLoadTracker::RecordRappor() { | 350 void PageLoadTracker::RecordRappor() { |
| 332 DCHECK(!GetCommittedURL().is_empty()); | 351 DCHECK(!committed_url().is_empty()); |
| 333 rappor::RapporService* rappor_service = | 352 rappor::RapporService* rappor_service = |
| 334 embedder_interface_->GetRapporService(); | 353 embedder_interface_->GetRapporService(); |
| 335 if (!rappor_service) | 354 if (!rappor_service) |
| 336 return; | 355 return; |
| 337 base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_); | 356 base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_); |
| 338 // Log the eTLD+1 of sites that show poor loading performance. | 357 // Log the eTLD+1 of sites that show poor loading performance. |
| 339 if (!first_contentful_paint.is_zero() && | 358 if (!first_contentful_paint.is_zero() && |
| 340 first_contentful_paint < GetBackgroundDelta()) { | 359 first_contentful_paint < GetBackgroundDelta()) { |
| 341 scoped_ptr<rappor::Sample> sample = | 360 scoped_ptr<rappor::Sample> sample = |
| 342 rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE); | 361 rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE); |
| 343 sample->SetStringField("Domain", rappor::GetDomainAndRegistrySampleFromGURL( | 362 sample->SetStringField( |
| 344 GetCommittedURL())); | 363 "Domain", rappor::GetDomainAndRegistrySampleFromGURL(committed_url())); |
| 345 uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint); | 364 uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint); |
| 346 sample->SetFlagsField("Bucket", uint64_t(1) << bucket_index, | 365 sample->SetFlagsField("Bucket", uint64_t(1) << bucket_index, |
| 347 kNumRapporHistogramBuckets); | 366 kNumRapporHistogramBuckets); |
| 348 // The IsSlow flag is just a one bit boolean if the first layout was > 10s. | 367 // The IsSlow flag is just a one bit boolean if the first layout was > 10s. |
| 349 sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10, | 368 sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10, |
| 350 1); | 369 1); |
| 351 rappor_service->RecordSampleObj(kRapporMetricsNameCoarseTiming, | 370 rappor_service->RecordSampleObj(kRapporMetricsNameCoarseTiming, |
| 352 sample.Pass()); | 371 sample.Pass()); |
| 353 } | 372 } |
| 354 } | 373 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 369 MetricsWebContentsObserver* metrics = FromWebContents(web_contents); | 388 MetricsWebContentsObserver* metrics = FromWebContents(web_contents); |
| 370 if (!metrics) { | 389 if (!metrics) { |
| 371 metrics = | 390 metrics = |
| 372 new MetricsWebContentsObserver(web_contents, embedder_interface.Pass()); | 391 new MetricsWebContentsObserver(web_contents, embedder_interface.Pass()); |
| 373 web_contents->SetUserData(UserDataKey(), metrics); | 392 web_contents->SetUserData(UserDataKey(), metrics); |
| 374 } | 393 } |
| 375 return metrics; | 394 return metrics; |
| 376 } | 395 } |
| 377 | 396 |
| 378 MetricsWebContentsObserver::~MetricsWebContentsObserver() { | 397 MetricsWebContentsObserver::~MetricsWebContentsObserver() { |
| 379 // Reset PageLoadTrackers so observers get final notifications. | 398 // The PageLoadTrackers must be deleted before the |embedded_interface_|. |
|
Randy Smith (Not in Mondays)
2015/12/05 14:13:28
nit: I've value a suffixed "because they contain a
| |
| 380 committed_load_.reset(); | 399 committed_load_.reset(); |
| 381 provisional_loads_.clear(); | 400 provisional_loads_.clear(); |
| 382 FOR_EACH_OBSERVER(PageLoadMetricsObserver, observers_, | |
| 383 OnPageLoadMetricsGoingAway()); | |
| 384 } | |
| 385 | |
| 386 void MetricsWebContentsObserver::AddObserver( | |
| 387 PageLoadMetricsObserver* observer) { | |
| 388 observers_.AddObserver(observer); | |
| 389 } | |
| 390 | |
| 391 void MetricsWebContentsObserver::RemoveObserver( | |
| 392 PageLoadMetricsObserver* observer) { | |
| 393 observers_.RemoveObserver(observer); | |
| 394 } | 401 } |
| 395 | 402 |
| 396 bool MetricsWebContentsObserver::OnMessageReceived( | 403 bool MetricsWebContentsObserver::OnMessageReceived( |
| 397 const IPC::Message& message, | 404 const IPC::Message& message, |
| 398 content::RenderFrameHost* render_frame_host) { | 405 content::RenderFrameHost* render_frame_host) { |
| 399 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 406 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 400 bool handled = true; | 407 bool handled = true; |
| 401 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message, | 408 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message, |
| 402 render_frame_host) | 409 render_frame_host) |
| 403 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) | 410 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) |
| 404 IPC_MESSAGE_UNHANDLED(handled = false) | 411 IPC_MESSAGE_UNHANDLED(handled = false) |
| 405 IPC_END_MESSAGE_MAP() | 412 IPC_END_MESSAGE_MAP() |
| 406 return handled; | 413 return handled; |
| 407 } | 414 } |
| 408 | 415 |
| 409 void MetricsWebContentsObserver::DidStartNavigation( | 416 void MetricsWebContentsObserver::DidStartNavigation( |
| 410 content::NavigationHandle* navigation_handle) { | 417 content::NavigationHandle* navigation_handle) { |
| 411 if (!navigation_handle->IsInMainFrame()) | 418 if (!navigation_handle->IsInMainFrame()) |
| 412 return; | 419 return; |
| 413 if (embedder_interface_->IsPrerendering(web_contents())) | 420 if (embedder_interface_->IsPrerendering(web_contents())) |
| 414 return; | 421 return; |
| 415 // We can have two provisional loads in some cases. E.g. a same-site | 422 // We can have two provisional loads in some cases. E.g. a same-site |
| 416 // navigation can have a concurrent cross-process navigation started | 423 // navigation can have a concurrent cross-process navigation started |
| 417 // from the omnibox. | 424 // from the omnibox. |
| 418 DCHECK_GT(2ul, provisional_loads_.size()); | 425 DCHECK_GT(2ul, provisional_loads_.size()); |
| 419 // Passing raw pointers to observers_ and embedder_interface_ is safe because | 426 // Passing raw pointers to observers_ and embedder_interface_ is safe because |
| 420 // the MetricsWebContentsObserver owns them both list and they are torn down | 427 // the MetricsWebContentsObserver owns them both list and they are torn down |
| 421 // after the PageLoadTracker. | 428 // after the PageLoadTracker. |
| 422 provisional_loads_.insert(std::make_pair( | 429 provisional_loads_.insert(std::make_pair( |
| 423 navigation_handle, make_scoped_ptr(new PageLoadTracker( | 430 navigation_handle, |
| 424 in_foreground_, embedder_interface_.get(), | 431 make_scoped_ptr(new PageLoadTracker( |
| 425 navigation_handle, &observers_)))); | 432 in_foreground_, embedder_interface_.get(), navigation_handle)))); |
| 426 } | 433 } |
| 427 | 434 |
| 428 void MetricsWebContentsObserver::DidFinishNavigation( | 435 void MetricsWebContentsObserver::DidFinishNavigation( |
| 429 content::NavigationHandle* navigation_handle) { | 436 content::NavigationHandle* navigation_handle) { |
| 430 if (!navigation_handle->IsInMainFrame()) | 437 if (!navigation_handle->IsInMainFrame()) |
| 431 return; | 438 return; |
| 432 | 439 |
| 433 scoped_ptr<PageLoadTracker> finished_nav( | 440 scoped_ptr<PageLoadTracker> finished_nav( |
| 434 std::move(provisional_loads_[navigation_handle])); | 441 std::move(provisional_loads_[navigation_handle])); |
| 435 provisional_loads_.erase(navigation_handle); | 442 provisional_loads_.erase(navigation_handle); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 449 : error == net::ERR_ABORTED ? PROVISIONAL_LOAD_ERR_ABORTED | 456 : error == net::ERR_ABORTED ? PROVISIONAL_LOAD_ERR_ABORTED |
| 450 : PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT); | 457 : PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT); |
| 451 return; | 458 return; |
| 452 } | 459 } |
| 453 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_COMMITTED); | 460 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_COMMITTED); |
| 454 | 461 |
| 455 // Don't treat a same-page nav as a new page load. | 462 // Don't treat a same-page nav as a new page load. |
| 456 if (navigation_handle->IsSamePage()) | 463 if (navigation_handle->IsSamePage()) |
| 457 return; | 464 return; |
| 458 | 465 |
| 459 // Eagerly log the previous UMA even if we don't care about the current | 466 committed_load_ = finished_nav.Pass(); |
| 460 // navigation. | |
| 461 committed_load_.reset(); | |
| 462 | 467 |
| 463 const GURL& browser_url = web_contents()->GetLastCommittedURL(); | 468 const GURL& browser_url = web_contents()->GetLastCommittedURL(); |
| 464 const std::string& mime_type = web_contents()->GetContentsMimeType(); | 469 const std::string& mime_type = web_contents()->GetContentsMimeType(); |
| 465 DCHECK(!browser_url.is_empty()); | 470 DCHECK(!browser_url.is_empty()); |
| 466 DCHECK(!mime_type.empty()); | 471 DCHECK(!mime_type.empty()); |
| 467 if (!IsRelevantNavigation(navigation_handle, browser_url, mime_type)) | 472 committed_load_->set_renderer_tracked( |
| 468 return; | 473 IsRelevantNavigation(navigation_handle, browser_url, mime_type)); |
| 469 | 474 |
| 470 committed_load_ = finished_nav.Pass(); | |
| 471 committed_load_->Commit(navigation_handle); | 475 committed_load_->Commit(navigation_handle); |
| 472 } | 476 } |
| 473 | 477 |
| 474 void MetricsWebContentsObserver::DidRedirectNavigation( | 478 void MetricsWebContentsObserver::DidRedirectNavigation( |
| 475 content::NavigationHandle* navigation_handle) { | 479 content::NavigationHandle* navigation_handle) { |
| 476 if (!navigation_handle->IsInMainFrame()) | 480 if (!navigation_handle->IsInMainFrame()) |
| 477 return; | 481 return; |
| 478 auto it = provisional_loads_.find(navigation_handle); | 482 auto it = provisional_loads_.find(navigation_handle); |
| 479 if (it == provisional_loads_.end()) | 483 if (it == provisional_loads_.end()) |
| 480 return; | 484 return; |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 504 // we have one. | 508 // we have one. |
| 505 void MetricsWebContentsObserver::RenderProcessGone( | 509 void MetricsWebContentsObserver::RenderProcessGone( |
| 506 base::TerminationStatus status) { | 510 base::TerminationStatus status) { |
| 507 committed_load_.reset(); | 511 committed_load_.reset(); |
| 508 } | 512 } |
| 509 | 513 |
| 510 void MetricsWebContentsObserver::OnTimingUpdated( | 514 void MetricsWebContentsObserver::OnTimingUpdated( |
| 511 content::RenderFrameHost* render_frame_host, | 515 content::RenderFrameHost* render_frame_host, |
| 512 const PageLoadTiming& timing) { | 516 const PageLoadTiming& timing) { |
| 513 bool error = false; | 517 bool error = false; |
| 514 if (!committed_load_) { | 518 if (!committed_load_ || !committed_load_->renderer_tracked()) { |
| 515 RecordInternalError(ERR_IPC_WITH_NO_COMMITTED_LOAD); | 519 RecordInternalError(ERR_IPC_WITH_NO_RELEVANT_LOAD); |
| 516 error = true; | 520 error = true; |
| 517 } | 521 } |
| 518 | 522 |
| 519 // We may receive notifications from frames that have been navigated away | 523 // We may receive notifications from frames that have been navigated away |
| 520 // from. We simply ignore them. | 524 // from. We simply ignore them. |
| 521 if (render_frame_host != web_contents()->GetMainFrame()) { | 525 if (render_frame_host != web_contents()->GetMainFrame()) { |
| 522 RecordInternalError(ERR_IPC_FROM_WRONG_FRAME); | 526 RecordInternalError(ERR_IPC_FROM_WRONG_FRAME); |
| 523 error = true; | 527 error = true; |
| 524 } | 528 } |
| 525 | 529 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 536 | 540 |
| 537 if (!committed_load_->UpdateTiming(timing)) { | 541 if (!committed_load_->UpdateTiming(timing)) { |
| 538 // If the page load tracker cannot update its timing, something is wrong | 542 // If the page load tracker cannot update its timing, something is wrong |
| 539 // with the IPC (it's from another load, or it's invalid in some other way). | 543 // with the IPC (it's from another load, or it's invalid in some other way). |
| 540 // We expect this to be a rare occurrence. | 544 // We expect this to be a rare occurrence. |
| 541 RecordInternalError(ERR_BAD_TIMING_IPC); | 545 RecordInternalError(ERR_BAD_TIMING_IPC); |
| 542 } | 546 } |
| 543 } | 547 } |
| 544 | 548 |
| 545 } // namespace page_load_metrics | 549 } // namespace page_load_metrics |
| OLD | NEW |