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

Unified 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: 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 side-by-side diff with in-line comments
Download patch
Index: components/page_load_metrics/browser/metrics_web_contents_observer.cc
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index 3e1db269cbc05761a974dd871614369af70141f7..b92ae7ba0f8eed69abbb98819226823a9e1d3a91 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -21,6 +21,7 @@
#include "content/public/browser/web_contents_user_data.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
+#include "ui/base/page_transition_types.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(
page_load_metrics::MetricsWebContentsObserver);
@@ -80,6 +81,15 @@ void RecordInternalError(InternalErrorLoadEvent event) {
UMA_HISTOGRAM_ENUMERATION(kErrorEvents, event, ERR_LAST_ENTRY);
}
+UserAbortType AbortTypeForPageTransition(ui::PageTransition transition) {
+ if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD))
+ return ABORT_RELOAD;
+ else if (transition & ui::PAGE_TRANSITION_FORWARD_BACK)
+ return ABORT_FORWARD_BACK;
+ else
+ return ABORT_NEW_NAVIGATION;
+}
+
base::TimeDelta GetFirstContentfulPaint(const PageLoadTiming& timing) {
if (timing.first_text_paint.is_zero())
return timing.first_image_paint;
@@ -120,6 +130,7 @@ PageLoadTracker::PageLoadTracker(
base::ObserverList<PageLoadMetricsObserver, true>* observers)
: has_commit_(false),
navigation_start_(navigation_handle->navigation_start()),
+ abort_type_(ABORT_NULL),
started_in_foreground_(in_foreground),
embedder_interface_(embedder_interface),
observers_(observers) {}
@@ -129,6 +140,7 @@ PageLoadTracker::~PageLoadTracker() {
RecordTimingHistograms();
RecordRappor();
}
+ RecordAbortTimingHistograms();
}
void PageLoadTracker::WebContentsHidden() {
@@ -178,14 +190,90 @@ bool PageLoadTracker::HasBackgrounded() {
PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() {
base::TimeDelta first_background_time;
base::TimeDelta first_foreground_time;
- if (!background_time_.is_null() && started_in_foreground_)
+ if (!background_time_.is_null())
first_background_time = background_time_ - navigation_start_;
- if (!foreground_time_.is_null() && !started_in_foreground_)
+ if (!foreground_time_.is_null())
first_foreground_time = foreground_time_ - navigation_start_;
return PageLoadExtraInfo(first_background_time, first_foreground_time,
started_in_foreground_);
}
+// We consider the first abort passed here as the true abort, unless it is
+// ABORT_OTHER, so call this with decreasing specificity.
+void PageLoadTracker::NotifyAbort(UserAbortType abort_type,
+ const base::TimeTicks& timestamp) {
+ DCHECK(abort_type != ABORT_NULL);
+ if (abort_type_ == ABORT_NULL) {
+ abort_type_ = abort_type;
+ abort_time_ = timestamp;
+ }
+
+ // If we got a better signal than ABORT_OTHER since the last navigation, treat
+ // it as the cause of the abort (Some ABORT_OTHER signals occur before the
+ // true signal). Note that this only occurs for provisional loads. While this
+ // heuristic is coarse, it works better and is simpler than other feasible
+ // methods.
+ if (abort_type_ == ABORT_OTHER && abort_type != ABORT_OTHER) {
+ abort_type_ = abort_type;
+ abort_time_ = std::min(abort_time_, timestamp);
+ }
+}
+
+void PageLoadTracker::RecordAbortTimingHistograms() {
+ // Log the background "abort" if we backgrounded a foregrounded page before
+ // its first paint. This is a slightly different notion of abort (we can still
+ // get to the first paint later), but it is still worthwhile measure.
+ if (!background_time_.is_null() &&
+ (timing_.first_paint.is_zero() ||
+ GetBackgroundDelta() < timing_.first_paint)) {
+ if (has_commit_) {
+ PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortBackground,
Bryan McQuade 2015/11/17 13:33:08 this does feel like a user-initiated abort, but i
Charlie Harrison 2015/11/17 16:11:54 I could go either way. I only put it here because
+ background_time_ - navigation_start_);
+ } else {
+ PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortBackground,
+ background_time_ - navigation_start_);
+ }
+ }
+ if (abort_type_ == ABORT_NULL)
+ return;
+ DCHECK(!abort_time_.is_null());
+
+ // Loads are not considered aborts if they painted before the abort event.
Bryan McQuade 2015/11/17 13:33:08 i'm inclined to either ignore aborts when a tab is
Charlie Harrison 2015/11/17 16:11:54 I'm inclined to ignore them for now and add later
+ base::TimeDelta time_to_abort = abort_time_ - navigation_start_;
+ if (!timing_.first_paint.is_zero() && timing_.first_paint < time_to_abort)
+ return;
+ if (has_commit_) {
+ if (abort_type_ == ABORT_RELOAD) {
+ PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortReload, time_to_abort);
+ } else if (abort_type_ == ABORT_FORWARD_BACK) {
+ PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortForwardBack, time_to_abort);
+ } else if (abort_type_ == ABORT_NEW_NAVIGATION) {
+ PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortNewNavigation, time_to_abort);
+ } else if (abort_type_ == ABORT_STOP) {
+ PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortStop, time_to_abort);
+ } else if (abort_type_ == ABORT_CLOSE) {
+ PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortClose, time_to_abort);
+ } else if (abort_type_ == ABORT_OTHER) {
+ PAGE_LOAD_HISTOGRAM(kHistogramCommittedAbortOther, time_to_abort);
+ }
+ } else {
+ if (abort_type_ == ABORT_RELOAD) {
+ PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortReload, time_to_abort);
+ } else if (abort_type_ == ABORT_FORWARD_BACK) {
+ PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortForwardBack, time_to_abort);
+ } else if (abort_type_ == ABORT_NEW_NAVIGATION) {
+ PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortNewNavigation,
+ time_to_abort);
+ } else if (abort_type_ == ABORT_STOP) {
+ PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortStop, time_to_abort);
+ } else if (abort_type_ == ABORT_CLOSE) {
+ PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortClose, time_to_abort);
+ } else if (abort_type_ == ABORT_OTHER) {
+ PAGE_LOAD_HISTOGRAM(kHistogramProvisionalAbortOther, time_to_abort);
+ }
+ }
+}
+
const GURL& PageLoadTracker::GetCommittedURL() {
DCHECK(has_commit_);
return url_;
@@ -370,8 +458,10 @@ MetricsWebContentsObserver* MetricsWebContentsObserver::CreateForWebContents(
MetricsWebContentsObserver::~MetricsWebContentsObserver() {
// Reset PageLoadTrackers so observers get final notifications.
+ NotifyAbortAllLoads(ABORT_CLOSE);
committed_load_.reset();
provisional_loads_.clear();
+ aborted_provisional_loads_.clear();
FOR_EACH_OBSERVER(PageLoadMetricsObserver, observers_,
OnPageLoadMetricsGoingAway());
}
@@ -433,12 +523,18 @@ void MetricsWebContentsObserver::DidFinishNavigation(
// Handle a pre-commit error here. Navigations that result in an error page
// will be ignored. Note that downloads/204s will result in HasCommitted()
// returning false.
+ // TODO(csharrison): Track changes to NavigationHandle for signals when this
+ // is the case (HTTP response headers).
if (!navigation_handle->HasCommitted()) {
net::Error error = navigation_handle->GetNetErrorCode();
- finished_nav->RecordProvisionalEvent(
- error == net::OK ? PROVISIONAL_LOAD_STOPPED
+ ProvisionalLoadEvent event = error == net::OK ? PROVISIONAL_LOAD_STOPPED
: error == net::ERR_ABORTED ? PROVISIONAL_LOAD_ERR_ABORTED
Bryan McQuade 2015/11/17 13:33:08 IIRC downloads/204s report ERR_ABORTED, so we'll e
Charlie Harrison 2015/11/17 16:11:54 Let's see. It's possible clamy@ will land her chan
- : PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT);
+ : PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT;
+ finished_nav->RecordProvisionalEvent(event);
+ if (event != PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT) {
+ finished_nav->NotifyAbort(ABORT_OTHER, base::TimeTicks::Now());
+ aborted_provisional_loads_.push_back(finished_nav.Pass());
Bryan McQuade 2015/11/17 13:33:08 the aborted_provisional_loads_ member makes me a b
+ }
return;
}
finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_COMMITTED);
Bryan McQuade 2015/11/17 13:33:08 just noticing now - unrelated to this change - sho
Charlie Harrison 2015/11/17 16:11:54 This was intentional. If we want we can break up t
@@ -447,6 +543,11 @@ void MetricsWebContentsObserver::DidFinishNavigation(
if (navigation_handle->IsSamePage())
return;
+ // Notify other loads that they may have been aborted by this committed load
+ NotifyAbortAllLoadsWithTimestamp(
+ AbortTypeForPageTransition(navigation_handle->GetPageTransition()),
+ navigation_handle->navigation_start());
+
// Eagerly log the previous UMA even if we don't care about the current
// navigation.
committed_load_.reset();
@@ -460,6 +561,11 @@ void MetricsWebContentsObserver::DidFinishNavigation(
committed_load_ = finished_nav.Pass();
committed_load_->Commit(navigation_handle);
+ aborted_provisional_loads_.clear();
Bryan McQuade 2015/11/17 13:33:08 should we clear aborted_provisional_loads_ even if
Charlie Harrison 2015/11/17 16:11:54 Yupp good idea. Done.
+}
+
+void MetricsWebContentsObserver::NavigationStopped() {
+ NotifyAbortAllLoads(ABORT_STOP);
}
void MetricsWebContentsObserver::WasShown() {
@@ -485,7 +591,26 @@ void MetricsWebContentsObserver::WasHidden() {
// we have one.
void MetricsWebContentsObserver::RenderProcessGone(
base::TerminationStatus status) {
+ NotifyAbortAllLoads(ABORT_CLOSE);
committed_load_.reset();
+ provisional_loads_.clear();
+ aborted_provisional_loads_.clear();
+}
+
+void MetricsWebContentsObserver::NotifyAbortAllLoads(UserAbortType abort_type) {
+ NotifyAbortAllLoadsWithTimestamp(abort_type, base::TimeTicks::Now());
+}
+
+void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp(
+ UserAbortType abort_type, const base::TimeTicks& timestamp) {
+ if (committed_load_)
+ committed_load_->NotifyAbort(abort_type, timestamp);
+ for (const auto& kv : provisional_loads_) {
+ kv.second->NotifyAbort(abort_type, timestamp);
+ }
+ for (const auto& plt : aborted_provisional_loads_) {
+ plt->NotifyAbort(abort_type, timestamp);
+ }
}
void MetricsWebContentsObserver::OnTimingUpdated(

Powered by Google App Engine
This is Rietveld 408576698