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 c9896b7d5e9aaa7fe08705a332477d05175d29cf..5039557a870d9105b727da9e2eddc1834b170424 100644 |
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc |
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc |
@@ -64,21 +64,6 @@ std::ostream& operator<<(std::ostream& os, |
return os; |
} |
-// The url we see from the renderer side is not always the same as what |
-// we see from the browser side (e.g. chrome://newtab). We want to be |
-// sure here that we aren't logging UMA for internal pages. |
-bool IsRelevantNavigation(content::NavigationHandle* navigation_handle, |
- const GURL& browser_url, |
- const std::string& mime_type) { |
- DCHECK(navigation_handle->HasCommitted()); |
- return navigation_handle->IsInMainFrame() && |
- !navigation_handle->IsSamePage() && |
- !navigation_handle->IsErrorPage() && |
- navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() && |
- browser_url.SchemeIsHTTPOrHTTPS() && |
- (mime_type == "text/html" || mime_type == "application/xhtml+xml"); |
-} |
- |
// If second is non-zero, first must also be non-zero and less than or equal to |
// second. |
bool EventsInOrder(const base::Optional<base::TimeDelta>& first, |
@@ -223,7 +208,8 @@ void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer, |
const PageLoadTiming& new_timing, |
const PageLoadMetadata& last_metadata, |
const PageLoadExtraInfo& extra_info) { |
- observer->OnTimingUpdate(new_timing, extra_info); |
+ if (last_timing != new_timing) |
+ observer->OnTimingUpdate(new_timing, extra_info); |
if (new_timing.dom_content_loaded_event_start && |
!last_timing.dom_content_loaded_event_start) |
observer->OnDomContentLoadedEventStart(new_timing, extra_info); |
@@ -256,7 +242,7 @@ PageLoadTracker::PageLoadTracker( |
content::NavigationHandle* navigation_handle, |
int aborted_chain_size, |
int aborted_chain_size_same_url) |
- : renderer_tracked_(false), |
+ : did_stop_tracking_(false), |
navigation_start_(navigation_handle->NavigationStart()), |
url_(navigation_handle->GetURL()), |
abort_type_(ABORT_NONE), |
@@ -273,9 +259,12 @@ PageLoadTracker::PageLoadTracker( |
} |
PageLoadTracker::~PageLoadTracker() { |
+ if (did_stop_tracking_) |
+ return; |
+ |
const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
- if (info.time_to_commit && renderer_tracked() && timing_.IsEmpty()) { |
+ if (info.time_to_commit && timing_.IsEmpty()) { |
RecordInternalError(ERR_NO_IPCS_RECEIVED); |
} |
// Recall that trackers that are given ABORT_UNKNOWN_NAVIGATION have their |
@@ -445,8 +434,8 @@ bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, |
return false; |
} |
-void PageLoadTracker::set_renderer_tracked(bool renderer_tracked) { |
- renderer_tracked_ = renderer_tracked; |
+void PageLoadTracker::StopTracking() { |
+ did_stop_tracking_ = true; |
} |
void PageLoadTracker::AddObserver( |
@@ -466,7 +455,7 @@ void PageLoadTracker::ClampBrowserTimestampIfInterProcessTimeTickSkew( |
// navigation_start_. If it is due to a code error and it gets clamped in this |
// function, on high resolution systems it should lead to a dcheck failure. |
- // TODO (shivanisha) Currently IsHighResolution is the best way to check |
+ // TODO(shivanisha): Currently IsHighResolution is the best way to check |
// if the clock is system-wide monotonic. However IsHighResolution |
// does a broader check to see if the clock in use is high resolution |
// which also implies it is system-wide monotonic (on Windows). |
@@ -646,12 +635,6 @@ void MetricsWebContentsObserver::DidStartNavigation( |
content::NavigationHandle* navigation_handle) { |
if (!navigation_handle->IsInMainFrame()) |
return; |
- if (embedder_interface_->IsPrerendering(web_contents())) |
- return; |
- if (embedder_interface_->IsNewTabPageUrl(navigation_handle->GetURL())) |
- return; |
- if (navigation_handle->GetURL().spec().compare(url::kAboutBlankURL) == 0) |
- return; |
std::unique_ptr<PageLoadTracker> last_aborted = |
NotifyAbortedProvisionalLoadsNewNavigation(navigation_handle); |
@@ -668,6 +651,14 @@ void MetricsWebContentsObserver::DidStartNavigation( |
chain_size = last_aborted->aborted_chain_size() + 1; |
} |
+ if (!ShouldTrackNavigation(navigation_handle)) |
+ return; |
+ |
+ // TODO(bmcquade): add support for tracking prerendered pages when they become |
+ // visible. |
+ if (embedder_interface_->IsPrerendering(web_contents())) |
+ return; |
+ |
// Pass in the last committed url to the PageLoadTracker. If the MWCO has |
// never observed a committed load, use the last committed url from this |
// WebContent's opener. This is more accurate than using referrers due to |
@@ -712,67 +703,75 @@ void MetricsWebContentsObserver::DidFinishNavigation( |
std::move(provisional_loads_[navigation_handle])); |
provisional_loads_.erase(navigation_handle); |
- // There's a chance a navigation could have started before we were added to a |
- // tab. Bail out early if this is the case. |
- if (!finished_nav) |
- return; |
+ const bool should_track = |
+ finished_nav && ShouldTrackNavigation(navigation_handle); |
- // 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()) { |
- finished_nav->FailedProvisionalLoad(navigation_handle); |
- |
- net::Error error = navigation_handle->GetNetErrorCode(); |
- |
- // net::OK: This case occurs when the NavigationHandle finishes and reports |
- // !HasCommitted(), but reports no net::Error. This should not occur |
- // pre-PlzNavigate, but afterwards it should represent the navigation |
- // stopped by the user before it was ready to commit. |
- // net::ERR_ABORTED: An aborted provisional load has error net::ERR_ABORTED. |
- // Note that this can come from some non user-initiated errors, such as |
- // downloads, or 204 responses. See crbug.com/542369. |
- if ((error == net::OK) || (error == net::ERR_ABORTED)) { |
- finished_nav->NotifyAbort(ABORT_OTHER, base::TimeTicks::Now(), true); |
- aborted_provisional_loads_.push_back(std::move(finished_nav)); |
- } |
+ if (finished_nav && !should_track) |
+ finished_nav->StopTracking(); |
- return; |
+ if (navigation_handle->HasCommitted()) { |
+ // Ignore same-page navigations. |
+ if (navigation_handle->IsSamePage()) |
+ return; |
+ |
+ // Notify other loads that they may have been aborted by this committed |
+ // load. Note that by using the committed navigation start as the abort |
+ // cause, we lose data on provisional loads that were aborted by other |
+ // provisional loads. Those will either be listed as ABORT_OTHER or as being |
+ // aborted by this load. |
+ // is_certainly_browser_timestamp is set to false because NavigationStart() |
+ // could be set in either the renderer or browser process. |
+ NotifyAbortAllLoadsWithTimestamp( |
+ AbortTypeForPageTransition(navigation_handle->GetPageTransition()), |
+ navigation_handle->NavigationStart(), false); |
+ |
+ if (should_track) { |
+ HandleCommittedNavigationForTrackedLoad(navigation_handle, |
+ std::move(finished_nav)); |
+ } else { |
+ committed_load_.reset(); |
+ } |
+ } else if (should_track) { |
+ HandleFailedNavigationForTrackedLoad(navigation_handle, |
+ std::move(finished_nav)); |
} |
+} |
- // Don't treat a same-page nav as a new page load. |
- if (navigation_handle->IsSamePage()) |
- return; |
+// Handle a pre-commit error. 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). |
+void MetricsWebContentsObserver::HandleFailedNavigationForTrackedLoad( |
+ content::NavigationHandle* navigation_handle, |
+ std::unique_ptr<PageLoadTracker> tracker) { |
+ tracker->FailedProvisionalLoad(navigation_handle); |
+ |
+ net::Error error = navigation_handle->GetNetErrorCode(); |
+ |
+ // net::OK: This case occurs when the NavigationHandle finishes and reports |
+ // !HasCommitted(), but reports no net::Error. This should not occur |
+ // pre-PlzNavigate, but afterwards it should represent the navigation stopped |
+ // by the user before it was ready to commit. |
+ // net::ERR_ABORTED: An aborted provisional load has error |
+ // net::ERR_ABORTED. Note that this can come from some non user-initiated |
+ // errors, such as downloads, or 204 responses. See crbug.com/542369. |
+ if ((error == net::OK) || (error == net::ERR_ABORTED)) { |
+ tracker->NotifyAbort(ABORT_OTHER, base::TimeTicks::Now(), true); |
+ aborted_provisional_loads_.push_back(std::move(tracker)); |
+ } |
+} |
+void MetricsWebContentsObserver::HandleCommittedNavigationForTrackedLoad( |
+ content::NavigationHandle* navigation_handle, |
+ std::unique_ptr<PageLoadTracker> tracker) { |
if (!navigation_handle->HasUserGesture() && |
(navigation_handle->GetPageTransition() & |
ui::PAGE_TRANSITION_CLIENT_REDIRECT) != 0 && |
committed_load_) |
- committed_load_->NotifyClientRedirectTo(*finished_nav); |
- |
- // Notify other loads that they may have been aborted by this committed load. |
- // Note that by using the committed navigation start as the abort cause, we |
- // lose data on provisional loads that were aborted by other provisional |
- // loads. Those will either be listed as ABORT_OTHER or as being aborted by |
- // this load. |
- // is_certainly_browser_timestamp is set to false because NavigationStart() |
- // could be set in either the renderer or browser process. |
- NotifyAbortAllLoadsWithTimestamp( |
- AbortTypeForPageTransition(navigation_handle->GetPageTransition()), |
- navigation_handle->NavigationStart(), false); |
- |
- committed_load_ = std::move(finished_nav); |
- aborted_provisional_loads_.clear(); |
- |
- const GURL& browser_url = web_contents()->GetLastCommittedURL(); |
- const std::string& mime_type = web_contents()->GetContentsMimeType(); |
- DCHECK(!browser_url.is_empty()); |
- DCHECK(!mime_type.empty()); |
- committed_load_->set_renderer_tracked( |
- IsRelevantNavigation(navigation_handle, browser_url, mime_type)); |
+ committed_load_->NotifyClientRedirectTo(*tracker); |
+ committed_load_ = std::move(tracker); |
committed_load_->Commit(navigation_handle); |
} |
@@ -894,7 +893,7 @@ void MetricsWebContentsObserver::OnTimingUpdated( |
const PageLoadTiming& timing, |
const PageLoadMetadata& metadata) { |
bool error = false; |
- if (!committed_load_ || !committed_load_->renderer_tracked()) { |
+ if (!committed_load_) { |
RecordInternalError(ERR_IPC_WITH_NO_RELEVANT_LOAD); |
error = true; |
} |
@@ -925,4 +924,21 @@ void MetricsWebContentsObserver::OnTimingUpdated( |
} |
} |
+bool MetricsWebContentsObserver::ShouldTrackNavigation( |
+ content::NavigationHandle* navigation_handle) const { |
+ DCHECK(navigation_handle->IsInMainFrame()); |
+ if (!navigation_handle->GetURL().SchemeIsHTTPOrHTTPS()) |
+ return false; |
+ if (embedder_interface_->IsNewTabPageUrl(navigation_handle->GetURL())) |
+ return false; |
+ if (navigation_handle->HasCommitted()) { |
+ if (navigation_handle->IsSamePage() || navigation_handle->IsErrorPage()) |
+ return false; |
+ const std::string& mime_type = web_contents()->GetContentsMimeType(); |
+ if (mime_type != "text/html" && mime_type != "application/xhtml+xml") |
+ return false; |
+ } |
+ return true; |
+} |
+ |
} // namespace page_load_metrics |