Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(276)

Side by Side Diff: components/page_load_metrics/browser/metrics_web_contents_observer.cc

Issue 1449253002: [do not review][page_load_metrics] User Initiated Abort Tracking (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@plm_navigation_start
Patch Set: Add 100ms condition to overriding ABORT_OTHER. Remove ABORT_OTHER for committed loads Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698