| 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/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "components/page_load_metrics/common/page_load_metrics_messages.h" | 9 #include "components/page_load_metrics/common/page_load_metrics_messages.h" |
| 10 #include "components/page_load_metrics/common/page_load_timing.h" | 10 #include "components/page_load_metrics/common/page_load_timing.h" |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 } | 57 } |
| 58 | 58 |
| 59 } // namespace | 59 } // namespace |
| 60 | 60 |
| 61 #define PAGE_LOAD_HISTOGRAM(name, sample) \ | 61 #define PAGE_LOAD_HISTOGRAM(name, sample) \ |
| 62 UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \ | 62 UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \ |
| 63 base::TimeDelta::FromMilliseconds(10), \ | 63 base::TimeDelta::FromMilliseconds(10), \ |
| 64 base::TimeDelta::FromMinutes(10), 100) | 64 base::TimeDelta::FromMinutes(10), 100) |
| 65 | 65 |
| 66 PageLoadTracker::PageLoadTracker(bool in_foreground) | 66 PageLoadTracker::PageLoadTracker(bool in_foreground) |
| 67 : has_commit_(false), started_in_foreground_(in_foreground) { | 67 : has_commit_(false), started_in_foreground_(in_foreground) {} |
| 68 RecordEvent(PAGE_LOAD_STARTED); | |
| 69 } | |
| 70 | 68 |
| 71 PageLoadTracker::~PageLoadTracker() { | 69 PageLoadTracker::~PageLoadTracker() { |
| 72 // Even a load that failed a provisional load should log | |
| 73 // that it aborted before first layout. | |
| 74 if (timing_.first_layout.is_zero()) | |
| 75 RecordEvent(PAGE_LOAD_ABORTED_BEFORE_FIRST_LAYOUT); | |
| 76 | |
| 77 if (has_commit_) | 70 if (has_commit_) |
| 78 RecordTimingHistograms(); | 71 RecordTimingHistograms(); |
| 79 } | 72 } |
| 80 | 73 |
| 81 void PageLoadTracker::WebContentsHidden() { | 74 void PageLoadTracker::WebContentsHidden() { |
| 82 // Only log the first time we background in a given page load. | 75 // Only log the first time we background in a given page load. |
| 83 if (background_time_.is_null()) { | 76 if (started_in_foreground_ && background_time_.is_null()) |
| 84 background_time_ = base::TimeTicks::Now(); | 77 background_time_ = base::TimeTicks::Now(); |
| 85 } | 78 } |
| 79 |
| 80 void PageLoadTracker::WebContentsShown() { |
| 81 // Only log the first time we foreground in a given page load. |
| 82 // Don't log foreground time if we started foregrounded. |
| 83 if (!started_in_foreground_ && foreground_time_.is_null()) |
| 84 foreground_time_ = base::TimeTicks::Now(); |
| 86 } | 85 } |
| 87 | 86 |
| 88 void PageLoadTracker::Commit() { | 87 void PageLoadTracker::Commit() { |
| 89 has_commit_ = true; | 88 has_commit_ = true; |
| 89 if (started_in_foreground_) |
| 90 RecordCommittedEvent(COMMITTED_LOAD_STARTED_IN_FOREGROUND); |
| 91 else |
| 92 RecordCommittedEvent(COMMITTED_LOAD_STARTED_IN_BACKGROUND); |
| 90 } | 93 } |
| 91 | 94 |
| 92 bool PageLoadTracker::UpdateTiming(const PageLoadTiming& timing) { | 95 bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing) { |
| 93 // Throw away IPCs that are not relevant to the current navigation. | 96 // Throw away IPCs that are not relevant to the current navigation. |
| 94 if (!timing_.navigation_start.is_null() && | 97 // A valid timing struct is one that has the same navigation start as the |
| 95 timing_.navigation_start != timing.navigation_start) { | 98 // previous one (if the previous one had a navigation start at all). |
| 96 // TODO(csharrison) uma log a counter here | 99 bool valid_timing_descendent = |
| 97 return false; | 100 timing_.navigation_start.is_null() || |
| 98 } | 101 timing_.navigation_start == new_timing.navigation_start; |
| 99 if (IsValidPageLoadTiming(timing)) { | 102 if (IsValidPageLoadTiming(new_timing) && valid_timing_descendent) { |
| 100 timing_ = timing; | 103 timing_ = new_timing; |
| 101 return true; | 104 return true; |
| 102 } | 105 } |
| 106 RecordCommittedEvent(COMMITTED_LOAD_BAD_IPC); |
| 103 return false; | 107 return false; |
| 104 } | 108 } |
| 105 | 109 |
| 106 void PageLoadTracker::RecordTimingHistograms() { | 110 void PageLoadTracker::RecordTimingHistograms() { |
| 107 DCHECK(has_commit_); | 111 DCHECK(has_commit_); |
| 108 // This method is similar to how blink converts TimeTicks to epoch time. | 112 // This method is similar to how blink converts TimeTicks to epoch time. |
| 109 // There may be slight inaccuracies due to inter-process timestamps, but | 113 // There may be slight inaccuracies due to inter-process timestamps, but |
| 110 // this solution is the best we have right now. | 114 // this solution is the best we have right now. |
| 111 base::TimeDelta background_delta; | 115 base::TimeDelta background_delta; |
| 112 if (started_in_foreground_) { | 116 if (started_in_foreground_) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 128 } | 132 } |
| 129 if (!timing_.load_event_start.is_zero()) { | 133 if (!timing_.load_event_start.is_zero()) { |
| 130 if (timing_.load_event_start < background_delta) { | 134 if (timing_.load_event_start < background_delta) { |
| 131 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired", | 135 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired", |
| 132 timing_.load_event_start); | 136 timing_.load_event_start); |
| 133 } else { | 137 } else { |
| 134 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired.BG", | 138 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired.BG", |
| 135 timing_.load_event_start); | 139 timing_.load_event_start); |
| 136 } | 140 } |
| 137 } | 141 } |
| 138 if (!timing_.first_layout.is_zero()) { | 142 if (timing_.first_layout.is_zero()) { |
| 143 RecordCommittedEvent(COMMITTED_LOAD_ABORTED_BEFORE_FIRST_LAYOUT); |
| 144 } else { |
| 139 if (timing_.first_layout < background_delta) { | 145 if (timing_.first_layout < background_delta) { |
| 140 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout", | 146 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout", |
| 141 timing_.first_layout); | 147 timing_.first_layout); |
| 142 RecordEvent(PAGE_LOAD_SUCCESSFUL_FIRST_LAYOUT_FOREGROUND); | 148 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT_FOREGROUND); |
| 143 } else { | 149 } else { |
| 144 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout.BG", | 150 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout.BG", |
| 145 timing_.first_layout); | 151 timing_.first_layout); |
| 146 RecordEvent(PAGE_LOAD_SUCCESSFUL_FIRST_LAYOUT_BACKGROUND); | 152 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT_BACKGROUND); |
| 147 } | 153 } |
| 148 } | 154 } |
| 149 | 155 // Log time to first foreground / time to first background. Log counts that we |
| 156 // started a relevant page load in the foreground / background. |
| 157 if (!background_time_.is_null()) { |
| 158 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstBackground", |
| 159 background_delta); |
| 160 } else if (!foreground_time_.is_null()) { |
| 161 PAGE_LOAD_HISTOGRAM( |
| 162 "PageLoad.Timing2.NavigationToFirstForeground", |
| 163 WallTimeFromTimeTicks(foreground_time_) - timing_.navigation_start); |
| 164 } |
| 150 } | 165 } |
| 151 | 166 |
| 152 void PageLoadTracker::RecordEvent(PageLoadEvent event) { | 167 void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) { |
| 153 UMA_HISTOGRAM_ENUMERATION( | 168 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Provisional", event, |
| 154 "PageLoad.EventCounts", event, PAGE_LOAD_LAST_ENTRY); | 169 PROVISIONAL_LOAD_LAST_ENTRY); |
| 170 } |
| 171 |
| 172 void PageLoadTracker::RecordCommittedEvent(CommittedLoadEvent event) { |
| 173 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Committed", event, |
| 174 COMMITTED_LOAD_LAST_ENTRY); |
| 155 } | 175 } |
| 156 | 176 |
| 157 MetricsWebContentsObserver::MetricsWebContentsObserver( | 177 MetricsWebContentsObserver::MetricsWebContentsObserver( |
| 158 content::WebContents* web_contents) | 178 content::WebContents* web_contents) |
| 159 : content::WebContentsObserver(web_contents), in_foreground_(false) {} | 179 : content::WebContentsObserver(web_contents), in_foreground_(false) {} |
| 160 | 180 |
| 161 MetricsWebContentsObserver::~MetricsWebContentsObserver() {} | 181 MetricsWebContentsObserver::~MetricsWebContentsObserver() {} |
| 162 | 182 |
| 163 bool MetricsWebContentsObserver::OnMessageReceived( | 183 bool MetricsWebContentsObserver::OnMessageReceived( |
| 164 const IPC::Message& message, | 184 const IPC::Message& message, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 190 if (!navigation_handle->IsInMainFrame()) | 210 if (!navigation_handle->IsInMainFrame()) |
| 191 return; | 211 return; |
| 192 | 212 |
| 193 scoped_ptr<PageLoadTracker> finished_nav( | 213 scoped_ptr<PageLoadTracker> finished_nav( |
| 194 provisional_loads_.take_and_erase(navigation_handle)); | 214 provisional_loads_.take_and_erase(navigation_handle)); |
| 195 DCHECK(finished_nav); | 215 DCHECK(finished_nav); |
| 196 | 216 |
| 197 // Handle a pre-commit error here. Navigations that result in an error page | 217 // Handle a pre-commit error here. Navigations that result in an error page |
| 198 // will be ignored. | 218 // will be ignored. |
| 199 if (!navigation_handle->HasCommitted()) { | 219 if (!navigation_handle->HasCommitted()) { |
| 200 finished_nav->RecordEvent(PAGE_LOAD_FAILED_BEFORE_COMMIT); | |
| 201 if (navigation_handle->GetNetErrorCode() == net::ERR_ABORTED) | 220 if (navigation_handle->GetNetErrorCode() == net::ERR_ABORTED) |
| 202 finished_nav->RecordEvent(PAGE_LOAD_ABORTED_BEFORE_COMMIT); | 221 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_ABORTED); |
| 222 else |
| 223 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_FAILED_NON_ABORT); |
| 203 return; | 224 return; |
| 204 } | 225 } |
| 226 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_COMMITTED); |
| 205 | 227 |
| 206 // Don't treat a same-page nav as a new page load. | 228 // Don't treat a same-page nav as a new page load. |
| 207 if (navigation_handle->IsSamePage()) | 229 if (navigation_handle->IsSamePage()) |
| 208 return; | 230 return; |
| 209 | 231 |
| 210 // Eagerly log the previous UMA even if we don't care about the current | 232 // Eagerly log the previous UMA even if we don't care about the current |
| 211 // navigation. | 233 // navigation. |
| 212 committed_load_.reset(); | 234 committed_load_.reset(); |
| 213 | 235 |
| 214 if (!IsRelevantNavigation(navigation_handle)) | 236 if (!IsRelevantNavigation(navigation_handle)) |
| 215 return; | 237 return; |
| 216 | 238 |
| 217 committed_load_ = finished_nav.Pass(); | 239 committed_load_ = finished_nav.Pass(); |
| 218 committed_load_->Commit(); | 240 committed_load_->Commit(); |
| 219 } | 241 } |
| 220 | 242 |
| 221 void MetricsWebContentsObserver::WasShown() { | 243 void MetricsWebContentsObserver::WasShown() { |
| 222 in_foreground_ = true; | 244 in_foreground_ = true; |
| 245 if (committed_load_) |
| 246 committed_load_->WebContentsShown(); |
| 247 for (const auto& kv : provisional_loads_) { |
| 248 kv.second->WebContentsShown(); |
| 249 } |
| 223 } | 250 } |
| 224 | 251 |
| 225 void MetricsWebContentsObserver::WasHidden() { | 252 void MetricsWebContentsObserver::WasHidden() { |
| 226 in_foreground_ = false; | 253 in_foreground_ = false; |
| 227 if (committed_load_) | 254 if (committed_load_) |
| 228 committed_load_->WebContentsHidden(); | 255 committed_load_->WebContentsHidden(); |
| 229 for (const auto& kv : provisional_loads_) { | 256 for (const auto& kv : provisional_loads_) { |
| 230 kv.second->WebContentsHidden(); | 257 kv.second->WebContentsHidden(); |
| 231 } | 258 } |
| 232 } | 259 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 // sure here that we aren't logging UMA for internal pages. | 293 // sure here that we aren't logging UMA for internal pages. |
| 267 const GURL& browser_url = web_contents()->GetLastCommittedURL(); | 294 const GURL& browser_url = web_contents()->GetLastCommittedURL(); |
| 268 return navigation_handle->IsInMainFrame() && | 295 return navigation_handle->IsInMainFrame() && |
| 269 !navigation_handle->IsSamePage() && | 296 !navigation_handle->IsSamePage() && |
| 270 !navigation_handle->IsErrorPage() && | 297 !navigation_handle->IsErrorPage() && |
| 271 navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() && | 298 navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() && |
| 272 browser_url.SchemeIsHTTPOrHTTPS(); | 299 browser_url.SchemeIsHTTPOrHTTPS(); |
| 273 } | 300 } |
| 274 | 301 |
| 275 } // namespace page_load_metrics | 302 } // namespace page_load_metrics |
| OLD | NEW |