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" |
11 #include "components/page_load_metrics/browser/page_load_metrics_macros.h" | 11 #include "components/page_load_metrics/browser/page_load_metrics_macros.h" |
12 #include "components/page_load_metrics/common/page_load_metrics_messages.h" | 12 #include "components/page_load_metrics/common/page_load_metrics_messages.h" |
13 #include "components/page_load_metrics/common/page_load_timing.h" | 13 #include "components/page_load_metrics/common/page_load_timing.h" |
14 #include "components/rappor/rappor_service.h" | 14 #include "components/rappor/rappor_service.h" |
15 #include "components/rappor/rappor_utils.h" | 15 #include "components/rappor/rappor_utils.h" |
16 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
17 #include "content/public/browser/navigation_details.h" | 17 #include "content/public/browser/navigation_details.h" |
18 #include "content/public/browser/navigation_handle.h" | 18 #include "content/public/browser/navigation_handle.h" |
19 #include "content/public/browser/render_frame_host.h" | 19 #include "content/public/browser/render_frame_host.h" |
20 #include "content/public/browser/web_contents.h" | 20 #include "content/public/browser/web_contents.h" |
21 #include "content/public/browser/web_contents_observer.h" | 21 #include "content/public/browser/web_contents_observer.h" |
22 #include "content/public/browser/web_contents_user_data.h" | 22 #include "content/public/browser/web_contents_user_data.h" |
23 #include "ipc/ipc_message.h" | 23 #include "ipc/ipc_message.h" |
24 #include "ipc/ipc_message_macros.h" | 24 #include "ipc/ipc_message_macros.h" |
25 #include "ui/base/page_transition_types.h" | |
25 | 26 |
26 DEFINE_WEB_CONTENTS_USER_DATA_KEY( | 27 DEFINE_WEB_CONTENTS_USER_DATA_KEY( |
27 page_load_metrics::MetricsWebContentsObserver); | 28 page_load_metrics::MetricsWebContentsObserver); |
28 | 29 |
29 namespace page_load_metrics { | 30 namespace page_load_metrics { |
30 | 31 |
31 namespace { | 32 namespace { |
32 | 33 |
33 // The url we see from the renderer side is not always the same as what | 34 // The url we see from the renderer side is not always the same as what |
34 // we see from the browser side (e.g. chrome://newtab). We want to be | 35 // we see from the browser side (e.g. chrome://newtab). We want to be |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 return false; | 75 return false; |
75 } | 76 } |
76 | 77 |
77 return true; | 78 return true; |
78 } | 79 } |
79 | 80 |
80 void RecordInternalError(InternalErrorLoadEvent event) { | 81 void RecordInternalError(InternalErrorLoadEvent event) { |
81 UMA_HISTOGRAM_ENUMERATION(kErrorEvents, event, ERR_LAST_ENTRY); | 82 UMA_HISTOGRAM_ENUMERATION(kErrorEvents, event, ERR_LAST_ENTRY); |
82 } | 83 } |
83 | 84 |
85 UserAbortType AbortTypeForPageTransition(ui::PageTransition transition) { | |
86 if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD)) | |
Bryan McQuade
2015/11/23 22:39:44
any reason we use PageTransitionCoreTypeIs here bu
Charlie Harrison
2015/11/25 20:15:25
PAGE_TRANSITION_FORWARD_BACK is a qualifier, not a
| |
87 return ABORT_RELOAD; | |
88 else if (transition & ui::PAGE_TRANSITION_FORWARD_BACK) | |
89 return ABORT_FORWARD_BACK; | |
90 else | |
91 return ABORT_NEW_NAVIGATION; | |
92 } | |
93 | |
84 base::TimeDelta GetFirstContentfulPaint(const PageLoadTiming& timing) { | 94 base::TimeDelta GetFirstContentfulPaint(const PageLoadTiming& timing) { |
85 if (timing.first_text_paint.is_zero()) | 95 if (timing.first_text_paint.is_zero()) |
86 return timing.first_image_paint; | 96 return timing.first_image_paint; |
87 if (timing.first_image_paint.is_zero()) | 97 if (timing.first_image_paint.is_zero()) |
88 return timing.first_text_paint; | 98 return timing.first_text_paint; |
89 return std::min(timing.first_text_paint, timing.first_image_paint); | 99 return std::min(timing.first_text_paint, timing.first_image_paint); |
90 } | 100 } |
91 | 101 |
92 // The number of buckets in the bitfield histogram. These buckets are described | 102 // The number of buckets in the bitfield histogram. These buckets are described |
93 // in rappor.xml in PageLoad.CoarseTiming.NavigationToFirstContentfulPaint. | 103 // in rappor.xml in PageLoad.CoarseTiming.NavigationToFirstContentfulPaint. |
(...skipping 20 matching lines...) Expand all Loading... | |
114 | 124 |
115 } // namespace | 125 } // namespace |
116 | 126 |
117 PageLoadTracker::PageLoadTracker( | 127 PageLoadTracker::PageLoadTracker( |
118 bool in_foreground, | 128 bool in_foreground, |
119 PageLoadMetricsEmbedderInterface* embedder_interface, | 129 PageLoadMetricsEmbedderInterface* embedder_interface, |
120 content::NavigationHandle* navigation_handle, | 130 content::NavigationHandle* navigation_handle, |
121 base::ObserverList<PageLoadMetricsObserver, true>* observers) | 131 base::ObserverList<PageLoadMetricsObserver, true>* observers) |
122 : has_commit_(false), | 132 : has_commit_(false), |
123 navigation_start_(navigation_handle->NavigationStart()), | 133 navigation_start_(navigation_handle->NavigationStart()), |
134 abort_type_(ABORT_NONE), | |
124 started_in_foreground_(in_foreground), | 135 started_in_foreground_(in_foreground), |
125 embedder_interface_(embedder_interface), | 136 embedder_interface_(embedder_interface), |
126 observers_(observers) {} | 137 observers_(observers) {} |
127 | 138 |
128 PageLoadTracker::~PageLoadTracker() { | 139 PageLoadTracker::~PageLoadTracker() { |
129 if (has_commit_) { | 140 if (has_commit_) { |
130 RecordTimingHistograms(); | 141 RecordTimingHistograms(); |
131 RecordRappor(); | 142 RecordRappor(); |
132 } | 143 } |
144 RecordAbortTimingHistograms(); | |
133 } | 145 } |
134 | 146 |
135 void PageLoadTracker::WebContentsHidden() { | 147 void PageLoadTracker::WebContentsHidden() { |
136 // Only log the first time we background in a given page load. | 148 // Only log the first time we background in a given page load. |
137 if (started_in_foreground_ && background_time_.is_null()) | 149 if (started_in_foreground_ && background_time_.is_null()) |
138 background_time_ = base::TimeTicks::Now(); | 150 background_time_ = base::TimeTicks::Now(); |
139 } | 151 } |
140 | 152 |
141 void PageLoadTracker::WebContentsShown() { | 153 void PageLoadTracker::WebContentsShown() { |
142 // Only log the first time we foreground in a given page load. | 154 // Only log the first time we foreground in a given page load. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
177 return false; | 189 return false; |
178 } | 190 } |
179 | 191 |
180 bool PageLoadTracker::HasBackgrounded() { | 192 bool PageLoadTracker::HasBackgrounded() { |
181 return !started_in_foreground_ || !background_time_.is_null(); | 193 return !started_in_foreground_ || !background_time_.is_null(); |
182 } | 194 } |
183 | 195 |
184 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { | 196 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { |
185 base::TimeDelta first_background_time; | 197 base::TimeDelta first_background_time; |
186 base::TimeDelta first_foreground_time; | 198 base::TimeDelta first_foreground_time; |
187 if (!background_time_.is_null() && started_in_foreground_) | 199 if (!background_time_.is_null()) |
188 first_background_time = background_time_ - navigation_start_; | 200 first_background_time = background_time_ - navigation_start_; |
189 if (!foreground_time_.is_null() && !started_in_foreground_) | 201 if (!foreground_time_.is_null()) |
190 first_foreground_time = foreground_time_ - navigation_start_; | 202 first_foreground_time = foreground_time_ - navigation_start_; |
191 return PageLoadExtraInfo(first_background_time, first_foreground_time, | 203 return PageLoadExtraInfo(first_background_time, first_foreground_time, |
192 started_in_foreground_); | 204 started_in_foreground_); |
193 } | 205 } |
194 | 206 |
207 // We consider the first abort passed here as the true abort, unless it is | |
208 // ABORT_OTHER, so call this with decreasing specificity. | |
209 void PageLoadTracker::NotifyAbort(UserAbortType abort_type, | |
210 const base::TimeTicks& timestamp) { | |
211 DCHECK(abort_type != ABORT_NONE); | |
212 if (abort_type_ == ABORT_NONE) { | |
213 abort_type_ = abort_type; | |
214 abort_time_ = timestamp; | |
215 } | |
216 | |
217 // If we got a better signal than ABORT_OTHER in the last 100ms, treat it | |
218 // as the cause of the abort (Some ABORT_OTHER signals occur before the true | |
219 // signal). Note that this only occurs for provisional loads. While this | |
220 // heuristic is coarse, it works better and is simpler than other feasible | |
221 // methods. | |
Bryan McQuade
2015/11/23 22:39:44
Let's link to your design doc here so people readi
Charlie Harrison
2015/11/25 20:15:25
Done.
| |
222 if (abort_type_ == ABORT_OTHER && abort_type != ABORT_OTHER | |
223 && (timestamp - abort_time_).InMillisecondsF() < 100) { | |
224 abort_type_ = abort_type; | |
225 abort_time_ = std::min(abort_time_, timestamp); | |
Bryan McQuade
2015/11/23 22:39:44
do we ever expect timestamp to be less than abort_
Charlie Harrison
2015/11/25 20:15:25
I think it is possible. For instance if we get an
| |
226 } | |
227 } | |
228 | |
229 void PageLoadTracker::RecordAbortTimingHistograms() { | |
230 if (abort_type_ == ABORT_NONE) | |
231 return; | |
232 DCHECK(!abort_time_.is_null()); | |
233 | |
234 // Loads are not considered aborts if they painted before the abort event. | |
235 base::TimeDelta time_to_abort = abort_time_ - navigation_start_; | |
236 if (!timing_.first_paint.is_zero() && timing_.first_paint < time_to_abort) | |
237 return; | |
238 | |
239 // Don't log abort times if the page was backgrounded before the abort event. | |
240 if (GetBackgroundDelta() < time_to_abort) | |
241 return; | |
242 if (has_commit_) { | |
243 if (abort_type_ == ABORT_RELOAD) { | |
244 PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortReload, time_to_abort); | |
245 } else if (abort_type_ == ABORT_FORWARD_BACK) { | |
246 PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortForwardBack, time_to_abort); | |
247 } else if (abort_type_ == ABORT_NEW_NAVIGATION) { | |
248 PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortNewNavigation, time_to_abort); | |
249 } else if (abort_type_ == ABORT_STOP) { | |
250 PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortStop, time_to_abort); | |
251 } else if (abort_type_ == ABORT_CLOSE) { | |
252 PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortClose, time_to_abort); | |
253 } | |
Bryan McQuade
2015/11/23 21:33:42
can we add:
else {
DLOG(FATAL) << "Received ABORT_
Charlie Harrison
2015/11/25 20:15:25
Done.
| |
254 } else { | |
255 if (abort_type_ == ABORT_RELOAD) { | |
256 PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortReload, time_to_abort); | |
257 } else if (abort_type_ == ABORT_FORWARD_BACK) { | |
258 PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortForwardBack, time_to_abort); | |
259 } else if (abort_type_ == ABORT_NEW_NAVIGATION) { | |
260 PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortNewNavigation, | |
261 time_to_abort); | |
262 } else if (abort_type_ == ABORT_STOP) { | |
263 PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortStop, time_to_abort); | |
264 } else if (abort_type_ == ABORT_CLOSE) { | |
265 PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortClose, time_to_abort); | |
266 } else if (abort_type_ == ABORT_OTHER) { | |
267 PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortOther, time_to_abort); | |
268 } | |
269 } | |
270 } | |
271 | |
195 const GURL& PageLoadTracker::GetCommittedURL() { | 272 const GURL& PageLoadTracker::GetCommittedURL() { |
196 DCHECK(has_commit_); | 273 DCHECK(has_commit_); |
197 return url_; | 274 return url_; |
198 } | 275 } |
199 | 276 |
200 // Blink calculates navigation start using TimeTicks, but converts to epoch time | 277 // Blink calculates navigation start using TimeTicks, but converts to epoch time |
201 // in its public API. Thus, to compare time values to navigation start, we | 278 // in its public API. Thus, to compare time values to navigation start, we |
202 // calculate the current time since the epoch using TimeTicks, and convert to | 279 // calculate the current time since the epoch using TimeTicks, and convert to |
203 // Time. This method is similar to how blink converts TimeTicks to epoch time. | 280 // Time. This method is similar to how blink converts TimeTicks to epoch time. |
204 // There may be slight inaccuracies due to inter-process timestamps, but | 281 // There may be slight inaccuracies due to inter-process timestamps, but |
205 // this solution is the best we have right now. | 282 // this solution is the best we have right now. |
206 // | 283 // |
207 // returns a TimeDelta which is | 284 // returns a TimeDelta which is |
208 // - Infinity if we were never backgrounded | 285 // - Infinity if we were never backgrounded |
209 // - null (TimeDelta()) if we started backgrounded | 286 // - null (TimeDelta()) if we started backgrounded |
210 // - elapsed time to first background if we started in the foreground and | 287 // - elapsed time to first background if we started in the foreground and |
211 // backgrounded. | 288 // backgrounded. |
212 base::TimeDelta PageLoadTracker::GetBackgroundDelta() { | 289 base::TimeDelta PageLoadTracker::GetBackgroundDelta() { |
213 if (started_in_foreground_) { | 290 if (started_in_foreground_) { |
214 return background_time_.is_null() ? base::TimeDelta::Max() | 291 return background_time_.is_null() ? base::TimeDelta::Max() |
215 : background_time_ - navigation_start_; | 292 : background_time_ - navigation_start_; |
216 } | 293 } |
217 return base::TimeDelta(); | 294 return base::TimeDelta(); |
218 } | 295 } |
219 | 296 |
220 void PageLoadTracker::RecordTimingHistograms() { | 297 void PageLoadTracker::RecordTimingHistograms() { |
221 DCHECK(has_commit_); | 298 DCHECK(has_commit_); |
299 base::TimeDelta background_delta = GetBackgroundDelta(); | |
300 if (!background_time_.is_null() && (timing_.first_paint.is_zero() || | |
301 background_delta < timing_.first_paint)) { | |
302 PAGE_LOAD_HISTOGRAM(kHistogramBackgroundBeforePaint, | |
303 background_time_ - navigation_start_); | |
304 } | |
305 | |
306 // The rest of the timing histograms require us to have received IPCs from the | |
307 // renderer. Record UMA for how often this occurs (usually for quickly aborted | |
308 // loads). For now, don't update observers if this is the case. | |
222 if (timing_.IsEmpty()) { | 309 if (timing_.IsEmpty()) { |
223 RecordInternalError(ERR_NO_IPCS_RECEIVED); | 310 RecordInternalError(ERR_NO_IPCS_RECEIVED); |
224 return; | 311 return; |
225 } | 312 } |
226 | 313 |
227 PageLoadExtraInfo info = GetPageLoadMetricsInfo(); | 314 PageLoadExtraInfo info = GetPageLoadMetricsInfo(); |
228 FOR_EACH_OBSERVER(PageLoadMetricsObserver, *observers_, | 315 FOR_EACH_OBSERVER(PageLoadMetricsObserver, *observers_, |
229 OnComplete(timing_, info)); | 316 OnComplete(timing_, info)); |
230 | 317 |
231 base::TimeDelta background_delta = GetBackgroundDelta(); | |
232 | |
233 if (!timing_.dom_content_loaded_event_start.is_zero()) { | 318 if (!timing_.dom_content_loaded_event_start.is_zero()) { |
234 if (timing_.dom_content_loaded_event_start < background_delta) { | 319 if (timing_.dom_content_loaded_event_start < background_delta) { |
235 PAGE_LOAD_HISTOGRAM(kHistogramDomContentLoaded, | 320 PAGE_LOAD_HISTOGRAM(kHistogramDomContentLoaded, |
236 timing_.dom_content_loaded_event_start); | 321 timing_.dom_content_loaded_event_start); |
237 } else { | 322 } else { |
238 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramDomContentLoaded, | 323 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramDomContentLoaded, |
239 timing_.dom_content_loaded_event_start); | 324 timing_.dom_content_loaded_event_start); |
240 } | 325 } |
241 } | 326 } |
242 if (!timing_.load_event_start.is_zero()) { | 327 if (!timing_.load_event_start.is_zero()) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
288 PAGE_LOAD_HISTOGRAM(kHistogramFirstContentfulPaint, | 373 PAGE_LOAD_HISTOGRAM(kHistogramFirstContentfulPaint, |
289 first_contentful_paint); | 374 first_contentful_paint); |
290 } else { | 375 } else { |
291 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstContentfulPaint, | 376 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstContentfulPaint, |
292 first_contentful_paint); | 377 first_contentful_paint); |
293 } | 378 } |
294 } | 379 } |
295 | 380 |
296 // Log time to first foreground / time to first background. Log counts that we | 381 // Log time to first foreground / time to first background. Log counts that we |
297 // started a relevant page load in the foreground / background. | 382 // started a relevant page load in the foreground / background. |
298 if (!background_time_.is_null()) { | 383 if (!background_time_.is_null()) { |
Bryan McQuade
2015/11/23 22:39:44
should this be moved up above the timing_.IsEmpty(
| |
299 PAGE_LOAD_HISTOGRAM(kHistogramFirstBackground, background_delta); | 384 PAGE_LOAD_HISTOGRAM(kHistogramFirstBackground, background_delta); |
300 } else if (!foreground_time_.is_null()) { | 385 } else if (!foreground_time_.is_null()) { |
301 PAGE_LOAD_HISTOGRAM(kHistogramFirstForeground, | 386 PAGE_LOAD_HISTOGRAM(kHistogramFirstForeground, |
302 foreground_time_ - navigation_start_); | 387 foreground_time_ - navigation_start_); |
303 } | 388 } |
304 } | 389 } |
305 | 390 |
306 void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) { | 391 void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) { |
307 if (HasBackgrounded()) { | 392 if (HasBackgrounded()) { |
308 UMA_HISTOGRAM_ENUMERATION(kBackgroundProvisionalEvents, event, | 393 UMA_HISTOGRAM_ENUMERATION(kBackgroundProvisionalEvents, event, |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
369 if (!metrics) { | 454 if (!metrics) { |
370 metrics = | 455 metrics = |
371 new MetricsWebContentsObserver(web_contents, embedder_interface.Pass()); | 456 new MetricsWebContentsObserver(web_contents, embedder_interface.Pass()); |
372 web_contents->SetUserData(UserDataKey(), metrics); | 457 web_contents->SetUserData(UserDataKey(), metrics); |
373 } | 458 } |
374 return metrics; | 459 return metrics; |
375 } | 460 } |
376 | 461 |
377 MetricsWebContentsObserver::~MetricsWebContentsObserver() { | 462 MetricsWebContentsObserver::~MetricsWebContentsObserver() { |
378 // Reset PageLoadTrackers so observers get final notifications. | 463 // Reset PageLoadTrackers so observers get final notifications. |
464 NotifyAbortAllLoads(ABORT_CLOSE); | |
379 committed_load_.reset(); | 465 committed_load_.reset(); |
380 provisional_loads_.clear(); | 466 provisional_loads_.clear(); |
467 aborted_provisional_loads_.clear(); | |
381 FOR_EACH_OBSERVER(PageLoadMetricsObserver, observers_, | 468 FOR_EACH_OBSERVER(PageLoadMetricsObserver, observers_, |
382 OnPageLoadMetricsGoingAway()); | 469 OnPageLoadMetricsGoingAway()); |
383 } | 470 } |
384 | 471 |
385 void MetricsWebContentsObserver::AddObserver( | 472 void MetricsWebContentsObserver::AddObserver( |
386 PageLoadMetricsObserver* observer) { | 473 PageLoadMetricsObserver* observer) { |
387 observers_.AddObserver(observer); | 474 observers_.AddObserver(observer); |
388 } | 475 } |
389 | 476 |
390 void MetricsWebContentsObserver::RemoveObserver( | 477 void MetricsWebContentsObserver::RemoveObserver( |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
432 scoped_ptr<PageLoadTracker> finished_nav( | 519 scoped_ptr<PageLoadTracker> finished_nav( |
433 provisional_loads_.take_and_erase(navigation_handle)); | 520 provisional_loads_.take_and_erase(navigation_handle)); |
434 // There's a chance a navigation could have started before we were added to a | 521 // There's a chance a navigation could have started before we were added to a |
435 // tab. Bail out early if this is the case. | 522 // tab. Bail out early if this is the case. |
436 if (!finished_nav) | 523 if (!finished_nav) |
437 return; | 524 return; |
438 | 525 |
439 // Handle a pre-commit error here. Navigations that result in an error page | 526 // Handle a pre-commit error here. Navigations that result in an error page |
440 // will be ignored. Note that downloads/204s will result in HasCommitted() | 527 // will be ignored. Note that downloads/204s will result in HasCommitted() |
441 // returning false. | 528 // returning false. |
529 // TODO(csharrison): Track changes to NavigationHandle for signals when this | |
530 // is the case (HTTP response headers). | |
442 if (!navigation_handle->HasCommitted()) { | 531 if (!navigation_handle->HasCommitted()) { |
443 net::Error error = navigation_handle->GetNetErrorCode(); | 532 net::Error error = navigation_handle->GetNetErrorCode(); |
444 finished_nav->RecordProvisionalEvent( | 533 ProvisionalLoadEvent event = error == net::OK ? PROVISIONAL_LOAD_STOPPED |
445 error == net::OK ? PROVISIONAL_LOAD_STOPPED | |
446 : error == net::ERR_ABORTED ? PROVISIONAL_LOAD_ERR_ABORTED | 534 : error == net::ERR_ABORTED ? PROVISIONAL_LOAD_ERR_ABORTED |
447 : PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT); | 535 : PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT; |
536 finished_nav->RecordProvisionalEvent(event); | |
537 if (event != PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT) { | |
Bryan McQuade
2015/11/23 22:39:44
if event == PROVISIONAL_LOAD_STOPPED, should we pa
Charlie Harrison
2015/11/25 20:15:25
I think it should represent stop, but I'm not full
| |
538 finished_nav->NotifyAbort(ABORT_OTHER, base::TimeTicks::Now()); | |
539 aborted_provisional_loads_.push_back(finished_nav.Pass()); | |
540 } | |
448 return; | 541 return; |
449 } | 542 } |
450 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_COMMITTED); | 543 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_COMMITTED); |
451 | 544 |
452 // Don't treat a same-page nav as a new page load. | 545 // Don't treat a same-page nav as a new page load. |
453 if (navigation_handle->IsSamePage()) | 546 if (navigation_handle->IsSamePage()) |
454 return; | 547 return; |
455 | 548 |
549 // Notify other loads that they may have been aborted by this committed load. | |
550 // Note that by using the committed navigation start as the abort cause, we | |
551 // lose data on provisional loads that were aborted by other provisional | |
552 // loads. Those will either be listed as ABORT_OTHER or as being aborted by | |
553 // this load. | |
554 NotifyAbortAllLoadsWithTimestamp( | |
555 AbortTypeForPageTransition(navigation_handle->GetPageTransition()), | |
556 navigation_handle->NavigationStart()); | |
557 | |
456 // Eagerly log the previous UMA even if we don't care about the current | 558 // Eagerly log the previous UMA even if we don't care about the current |
457 // navigation. | 559 // navigation. |
458 committed_load_.reset(); | 560 committed_load_.reset(); |
561 aborted_provisional_loads_.clear(); | |
459 | 562 |
460 const GURL& browser_url = web_contents()->GetLastCommittedURL(); | 563 const GURL& browser_url = web_contents()->GetLastCommittedURL(); |
461 const std::string& mime_type = web_contents()->GetContentsMimeType(); | 564 const std::string& mime_type = web_contents()->GetContentsMimeType(); |
462 DCHECK(!browser_url.is_empty()); | 565 DCHECK(!browser_url.is_empty()); |
463 DCHECK(!mime_type.empty()); | 566 DCHECK(!mime_type.empty()); |
464 if (!IsRelevantNavigation(navigation_handle, browser_url, mime_type)) | 567 if (!IsRelevantNavigation(navigation_handle, browser_url, mime_type)) |
465 return; | 568 return; |
466 | 569 |
467 committed_load_ = finished_nav.Pass(); | 570 committed_load_ = finished_nav.Pass(); |
468 committed_load_->Commit(navigation_handle); | 571 committed_load_->Commit(navigation_handle); |
469 } | 572 } |
470 | 573 |
574 void MetricsWebContentsObserver::NavigationStopped() { | |
575 NotifyAbortAllLoads(ABORT_STOP); | |
576 } | |
577 | |
471 void MetricsWebContentsObserver::DidRedirectNavigation( | 578 void MetricsWebContentsObserver::DidRedirectNavigation( |
472 content::NavigationHandle* navigation_handle) { | 579 content::NavigationHandle* navigation_handle) { |
473 if (!navigation_handle->IsInMainFrame()) | 580 if (!navigation_handle->IsInMainFrame()) |
474 return; | 581 return; |
475 auto it = provisional_loads_.find(navigation_handle); | 582 auto it = provisional_loads_.find(navigation_handle); |
476 if (it == provisional_loads_.end()) | 583 if (it == provisional_loads_.end()) |
477 return; | 584 return; |
478 it->second->Redirect(navigation_handle); | 585 it->second->Redirect(navigation_handle); |
479 } | 586 } |
480 | 587 |
(...skipping 13 matching lines...) Expand all Loading... | |
494 for (const auto& kv : provisional_loads_) { | 601 for (const auto& kv : provisional_loads_) { |
495 kv.second->WebContentsHidden(); | 602 kv.second->WebContentsHidden(); |
496 } | 603 } |
497 } | 604 } |
498 | 605 |
499 // This will occur when the process for the main RenderFrameHost exits, either | 606 // This will occur when the process for the main RenderFrameHost exits, either |
500 // normally or from a crash. We eagerly log data from the last committed load if | 607 // normally or from a crash. We eagerly log data from the last committed load if |
501 // we have one. | 608 // we have one. |
502 void MetricsWebContentsObserver::RenderProcessGone( | 609 void MetricsWebContentsObserver::RenderProcessGone( |
503 base::TerminationStatus status) { | 610 base::TerminationStatus status) { |
611 NotifyAbortAllLoads(ABORT_CLOSE); | |
504 committed_load_.reset(); | 612 committed_load_.reset(); |
613 provisional_loads_.clear(); | |
614 aborted_provisional_loads_.clear(); | |
615 } | |
616 | |
617 void MetricsWebContentsObserver::NotifyAbortAllLoads(UserAbortType abort_type) { | |
618 NotifyAbortAllLoadsWithTimestamp(abort_type, base::TimeTicks::Now()); | |
619 } | |
620 | |
621 void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp( | |
622 UserAbortType abort_type, | |
623 const base::TimeTicks& timestamp) { | |
624 if (committed_load_) | |
625 committed_load_->NotifyAbort(abort_type, timestamp); | |
626 for (const auto& kv : provisional_loads_) { | |
627 kv.second->NotifyAbort(abort_type, timestamp); | |
628 } | |
629 for (const auto& plt : aborted_provisional_loads_) { | |
630 plt->NotifyAbort(abort_type, timestamp); | |
631 } | |
505 } | 632 } |
506 | 633 |
507 void MetricsWebContentsObserver::OnTimingUpdated( | 634 void MetricsWebContentsObserver::OnTimingUpdated( |
508 content::RenderFrameHost* render_frame_host, | 635 content::RenderFrameHost* render_frame_host, |
509 const PageLoadTiming& timing) { | 636 const PageLoadTiming& timing) { |
510 bool error = false; | 637 bool error = false; |
511 if (!committed_load_) { | 638 if (!committed_load_) { |
512 RecordInternalError(ERR_IPC_WITH_NO_COMMITTED_LOAD); | 639 RecordInternalError(ERR_IPC_WITH_NO_COMMITTED_LOAD); |
513 error = true; | 640 error = true; |
514 } | 641 } |
(...skipping 18 matching lines...) Expand all Loading... | |
533 | 660 |
534 if (!committed_load_->UpdateTiming(timing)) { | 661 if (!committed_load_->UpdateTiming(timing)) { |
535 // If the page load tracker cannot update its timing, something is wrong | 662 // If the page load tracker cannot update its timing, something is wrong |
536 // with the IPC (it's from another load, or it's invalid in some other way). | 663 // with the IPC (it's from another load, or it's invalid in some other way). |
537 // We expect this to be a rare occurrence. | 664 // We expect this to be a rare occurrence. |
538 RecordInternalError(ERR_BAD_TIMING_IPC); | 665 RecordInternalError(ERR_BAD_TIMING_IPC); |
539 } | 666 } |
540 } | 667 } |
541 | 668 |
542 } // namespace page_load_metrics | 669 } // namespace page_load_metrics |
OLD | NEW |