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_util.h" | 11 #include "components/page_load_metrics/browser/page_load_metrics_util.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)) | |
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 // The number of buckets in the bitfield histogram. These buckets are described | 94 // The number of buckets in the bitfield histogram. These buckets are described |
85 // in rappor.xml in PageLoad.CoarseTiming.NavigationToFirstContentfulPaint. | 95 // in rappor.xml in PageLoad.CoarseTiming.NavigationToFirstContentfulPaint. |
86 // The bucket flag is defined by 1 << bucket_index, and is the bitfield | 96 // The bucket flag is defined by 1 << bucket_index, and is the bitfield |
87 // representing which timing bucket the page load falls into, i.e. 000010 | 97 // representing which timing bucket the page load falls into, i.e. 000010 |
88 // would be the bucket flag showing that the page took between 2 and 4 seconds | 98 // would be the bucket flag showing that the page took between 2 and 4 seconds |
89 // to load. | 99 // to load. |
90 const size_t kNumRapporHistogramBuckets = 6; | 100 const size_t kNumRapporHistogramBuckets = 6; |
91 | 101 |
92 uint64_t RapporHistogramBucketIndex(const base::TimeDelta& time) { | 102 uint64_t RapporHistogramBucketIndex(const base::TimeDelta& time) { |
93 int64 seconds = time.InSeconds(); | 103 int64 seconds = time.InSeconds(); |
(...skipping 12 matching lines...) Expand all Loading... | |
106 | 116 |
107 } // namespace | 117 } // namespace |
108 | 118 |
109 PageLoadTracker::PageLoadTracker( | 119 PageLoadTracker::PageLoadTracker( |
110 bool in_foreground, | 120 bool in_foreground, |
111 PageLoadMetricsEmbedderInterface* embedder_interface, | 121 PageLoadMetricsEmbedderInterface* embedder_interface, |
112 content::NavigationHandle* navigation_handle) | 122 content::NavigationHandle* navigation_handle) |
113 : renderer_tracked_(false), | 123 : renderer_tracked_(false), |
114 has_commit_(false), | 124 has_commit_(false), |
115 navigation_start_(navigation_handle->NavigationStart()), | 125 navigation_start_(navigation_handle->NavigationStart()), |
126 abort_type_(ABORT_NONE), | |
116 started_in_foreground_(in_foreground), | 127 started_in_foreground_(in_foreground), |
117 embedder_interface_(embedder_interface) { | 128 embedder_interface_(embedder_interface) { |
118 embedder_interface_->RegisterObservers(this); | 129 embedder_interface_->RegisterObservers(this); |
119 for (const auto& observer : observers_) { | 130 for (const auto& observer : observers_) { |
120 observer->OnStart(navigation_handle); | 131 observer->OnStart(navigation_handle); |
121 } | 132 } |
122 } | 133 } |
123 | 134 |
124 PageLoadTracker::~PageLoadTracker() { | 135 PageLoadTracker::~PageLoadTracker() { |
125 if (has_commit_) { | |
126 RecordTimingHistograms(); | |
127 RecordRappor(); | |
128 } | |
129 PageLoadExtraInfo info = GetPageLoadMetricsInfo(); | 136 PageLoadExtraInfo info = GetPageLoadMetricsInfo(); |
137 if (has_commit_) | |
Bryan McQuade
2015/12/09 20:35:23
let's call all of the Record functions uncondition
Charlie Harrison
2015/12/09 22:46:44
Done.
| |
138 RecordRappor(info); | |
139 RecordTimingHistograms(info); | |
130 for (const auto& observer : observers_) { | 140 for (const auto& observer : observers_) { |
131 observer->OnComplete(timing_, info); | 141 observer->OnComplete(timing_, info); |
132 } | 142 } |
133 } | 143 } |
134 | 144 |
135 void PageLoadTracker::WebContentsHidden() { | 145 void PageLoadTracker::WebContentsHidden() { |
136 // Only log the first time we background in a given page load. | 146 // Only log the first time we background in a given page load. |
137 if (started_in_foreground_ && background_time_.is_null()) | 147 if (started_in_foreground_ && background_time_.is_null()) |
138 background_time_ = base::TimeTicks::Now(); | 148 background_time_ = base::TimeTicks::Now(); |
139 } | 149 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
189 } | 199 } |
190 | 200 |
191 void PageLoadTracker::AddObserver( | 201 void PageLoadTracker::AddObserver( |
192 scoped_ptr<PageLoadMetricsObserver> observer) { | 202 scoped_ptr<PageLoadMetricsObserver> observer) { |
193 observers_.push_back(std::move(observer)); | 203 observers_.push_back(std::move(observer)); |
194 } | 204 } |
195 | 205 |
196 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { | 206 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { |
197 base::TimeDelta first_background_time; | 207 base::TimeDelta first_background_time; |
198 base::TimeDelta first_foreground_time; | 208 base::TimeDelta first_foreground_time; |
209 base::TimeDelta time_to_abort; | |
199 if (!background_time_.is_null() && started_in_foreground_) | 210 if (!background_time_.is_null() && started_in_foreground_) |
200 first_background_time = background_time_ - navigation_start_; | 211 first_background_time = background_time_ - navigation_start_; |
201 if (!foreground_time_.is_null() && !started_in_foreground_) | 212 if (!foreground_time_.is_null() && !started_in_foreground_) |
202 first_foreground_time = foreground_time_ - navigation_start_; | 213 first_foreground_time = foreground_time_ - navigation_start_; |
214 if (abort_type_ != ABORT_NONE) | |
215 time_to_abort = abort_time_ - navigation_start_; | |
203 return PageLoadExtraInfo(first_background_time, first_foreground_time, | 216 return PageLoadExtraInfo(first_background_time, first_foreground_time, |
204 started_in_foreground_, has_commit_); | 217 started_in_foreground_, has_commit_, abort_type_, |
218 time_to_abort); | |
205 } | 219 } |
206 | 220 |
207 const GURL& PageLoadTracker::committed_url() { | 221 const GURL& PageLoadTracker::committed_url() { |
208 DCHECK(has_commit_); | 222 DCHECK(has_commit_); |
209 return url_; | 223 return url_; |
210 } | 224 } |
211 | 225 |
212 // Blink calculates navigation start using TimeTicks, but converts to epoch time | 226 // We consider the first abort passed here as the true abort, unless it is |
213 // in its public API. Thus, to compare time values to navigation start, we | 227 // ABORT_OTHER. |
214 // calculate the current time since the epoch using TimeTicks, and convert to | 228 void PageLoadTracker::NotifyAbort(UserAbortType abort_type, |
215 // Time. This method is similar to how blink converts TimeTicks to epoch time. | 229 const base::TimeTicks& timestamp) { |
216 // There may be slight inaccuracies due to inter-process timestamps, but | 230 DCHECK(abort_type != ABORT_NONE); |
217 // this solution is the best we have right now. | 231 if (abort_type_ == ABORT_NONE) { |
218 // | 232 abort_type_ = abort_type; |
219 // returns a TimeDelta which is | 233 abort_time_ = timestamp; |
220 // - Infinity if we were never backgrounded | |
221 // - null (TimeDelta()) if we started backgrounded | |
222 // - elapsed time to first background if we started in the foreground and | |
223 // backgrounded. | |
224 base::TimeDelta PageLoadTracker::GetBackgroundDelta() { | |
225 if (started_in_foreground_) { | |
226 return background_time_.is_null() ? base::TimeDelta::Max() | |
227 : background_time_ - navigation_start_; | |
228 } | 234 } |
229 return base::TimeDelta(); | 235 |
236 // If we got a better signal than ABORT_OTHER in the last 100ms, treat it | |
237 // as the cause of the abort (Some ABORT_OTHER signals occur before the true | |
238 // signal). Note that this only occurs for provisional loads. While this | |
239 // heuristic is coarse, it works better and is simpler than other feasible | |
240 // methods. See https://goo.gl/WKRG98. | |
241 if (abort_type_ == ABORT_OTHER && abort_type != ABORT_OTHER && | |
242 (timestamp - abort_time_).InMilliseconds() < 100) { | |
243 abort_type_ = abort_type; | |
244 abort_time_ = std::min(abort_time_, timestamp); | |
245 } | |
230 } | 246 } |
231 | 247 |
232 void PageLoadTracker::RecordTimingHistograms() { | 248 void PageLoadTracker::RecordTimingHistograms(const PageLoadExtraInfo& info) { |
233 DCHECK(has_commit_); | 249 base::TimeDelta background_delta = GetBackgroundDelta(info); |
234 if (!renderer_tracked()) | 250 if (!background_time_.is_null() && (timing_.first_paint.is_zero() || |
251 background_delta < timing_.first_paint)) { | |
252 if (has_commit_) { | |
253 PAGE_LOAD_HISTOGRAM(kHistogramBackgroundBeforePaint, | |
254 background_time_ - navigation_start_); | |
255 } else { | |
256 PAGE_LOAD_HISTOGRAM(kHistogramProvisionalBackground, | |
257 background_time_ - navigation_start_); | |
258 } | |
259 } | |
260 | |
261 // The rest of the histograms require the load to have commit and be relevant. | |
262 if (!has_commit_ || !renderer_tracked()) | |
235 return; | 263 return; |
236 | 264 |
265 // The rest of the timing histograms require us to have received IPCs from the | |
266 // renderer. Record UMA for how often this occurs (usually for quickly aborted | |
267 // loads). For now, don't update observers if this is the case. | |
237 if (timing_.IsEmpty()) { | 268 if (timing_.IsEmpty()) { |
238 RecordInternalError(ERR_NO_IPCS_RECEIVED); | 269 RecordInternalError(ERR_NO_IPCS_RECEIVED); |
239 return; | 270 return; |
240 } | 271 } |
241 | 272 |
242 base::TimeDelta background_delta = GetBackgroundDelta(); | |
243 | |
244 if (!timing_.dom_content_loaded_event_start.is_zero()) { | 273 if (!timing_.dom_content_loaded_event_start.is_zero()) { |
245 if (timing_.dom_content_loaded_event_start < background_delta) { | 274 if (timing_.dom_content_loaded_event_start < background_delta) { |
246 PAGE_LOAD_HISTOGRAM(kHistogramDomContentLoaded, | 275 PAGE_LOAD_HISTOGRAM(kHistogramDomContentLoaded, |
247 timing_.dom_content_loaded_event_start); | 276 timing_.dom_content_loaded_event_start); |
248 } else { | 277 } else { |
249 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramDomContentLoaded, | 278 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramDomContentLoaded, |
250 timing_.dom_content_loaded_event_start); | 279 timing_.dom_content_loaded_event_start); |
251 } | 280 } |
252 } | 281 } |
253 if (!timing_.load_event_start.is_zero()) { | 282 if (!timing_.load_event_start.is_zero()) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
340 bool backgrounded) { | 369 bool backgrounded) { |
341 if (backgrounded) { | 370 if (backgrounded) { |
342 UMA_HISTOGRAM_ENUMERATION(kBackgroundCommittedEvents, event, | 371 UMA_HISTOGRAM_ENUMERATION(kBackgroundCommittedEvents, event, |
343 RELEVANT_LOAD_LAST_ENTRY); | 372 RELEVANT_LOAD_LAST_ENTRY); |
344 } else { | 373 } else { |
345 UMA_HISTOGRAM_ENUMERATION(kCommittedEvents, event, | 374 UMA_HISTOGRAM_ENUMERATION(kCommittedEvents, event, |
346 RELEVANT_LOAD_LAST_ENTRY); | 375 RELEVANT_LOAD_LAST_ENTRY); |
347 } | 376 } |
348 } | 377 } |
349 | 378 |
350 void PageLoadTracker::RecordRappor() { | 379 void PageLoadTracker::RecordRappor(const PageLoadExtraInfo& info) { |
351 DCHECK(!committed_url().is_empty()); | 380 DCHECK(!committed_url().is_empty()); |
352 rappor::RapporService* rappor_service = | 381 rappor::RapporService* rappor_service = |
353 embedder_interface_->GetRapporService(); | 382 embedder_interface_->GetRapporService(); |
354 if (!rappor_service) | 383 if (!rappor_service) |
355 return; | 384 return; |
356 base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_); | 385 base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_); |
357 // Log the eTLD+1 of sites that show poor loading performance. | 386 // Log the eTLD+1 of sites that show poor loading performance. |
358 if (!first_contentful_paint.is_zero() && | 387 if (!first_contentful_paint.is_zero() && |
359 first_contentful_paint < GetBackgroundDelta()) { | 388 first_contentful_paint < GetBackgroundDelta(info)) { |
360 scoped_ptr<rappor::Sample> sample = | 389 scoped_ptr<rappor::Sample> sample = |
361 rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE); | 390 rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE); |
362 sample->SetStringField( | 391 sample->SetStringField( |
363 "Domain", rappor::GetDomainAndRegistrySampleFromGURL(committed_url())); | 392 "Domain", rappor::GetDomainAndRegistrySampleFromGURL(committed_url())); |
364 uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint); | 393 uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint); |
365 sample->SetFlagsField("Bucket", uint64_t(1) << bucket_index, | 394 sample->SetFlagsField("Bucket", uint64_t(1) << bucket_index, |
366 kNumRapporHistogramBuckets); | 395 kNumRapporHistogramBuckets); |
367 // The IsSlow flag is just a one bit boolean if the first layout was > 10s. | 396 // The IsSlow flag is just a one bit boolean if the first layout was > 10s. |
368 sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10, | 397 sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10, |
369 1); | 398 1); |
(...skipping 17 matching lines...) Expand all Loading... | |
387 | 416 |
388 MetricsWebContentsObserver* metrics = FromWebContents(web_contents); | 417 MetricsWebContentsObserver* metrics = FromWebContents(web_contents); |
389 if (!metrics) { | 418 if (!metrics) { |
390 metrics = | 419 metrics = |
391 new MetricsWebContentsObserver(web_contents, embedder_interface.Pass()); | 420 new MetricsWebContentsObserver(web_contents, embedder_interface.Pass()); |
392 web_contents->SetUserData(UserDataKey(), metrics); | 421 web_contents->SetUserData(UserDataKey(), metrics); |
393 } | 422 } |
394 return metrics; | 423 return metrics; |
395 } | 424 } |
396 | 425 |
397 MetricsWebContentsObserver::~MetricsWebContentsObserver() {} | 426 MetricsWebContentsObserver::~MetricsWebContentsObserver() { |
427 NotifyAbortAllLoads(ABORT_CLOSE); | |
428 } | |
398 | 429 |
399 bool MetricsWebContentsObserver::OnMessageReceived( | 430 bool MetricsWebContentsObserver::OnMessageReceived( |
400 const IPC::Message& message, | 431 const IPC::Message& message, |
401 content::RenderFrameHost* render_frame_host) { | 432 content::RenderFrameHost* render_frame_host) { |
402 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 433 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
403 bool handled = true; | 434 bool handled = true; |
404 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message, | 435 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message, |
405 render_frame_host) | 436 render_frame_host) |
406 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) | 437 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) |
407 IPC_MESSAGE_UNHANDLED(handled = false) | 438 IPC_MESSAGE_UNHANDLED(handled = false) |
(...skipping 30 matching lines...) Expand all Loading... | |
438 provisional_loads_.erase(navigation_handle); | 469 provisional_loads_.erase(navigation_handle); |
439 | 470 |
440 // There's a chance a navigation could have started before we were added to a | 471 // There's a chance a navigation could have started before we were added to a |
441 // tab. Bail out early if this is the case. | 472 // tab. Bail out early if this is the case. |
442 if (!finished_nav) | 473 if (!finished_nav) |
443 return; | 474 return; |
444 | 475 |
445 // Handle a pre-commit error here. Navigations that result in an error page | 476 // Handle a pre-commit error here. Navigations that result in an error page |
446 // will be ignored. Note that downloads/204s will result in HasCommitted() | 477 // will be ignored. Note that downloads/204s will result in HasCommitted() |
447 // returning false. | 478 // returning false. |
479 // TODO(csharrison): Track changes to NavigationHandle for signals when this | |
480 // is the case (HTTP response headers). | |
448 if (!navigation_handle->HasCommitted()) { | 481 if (!navigation_handle->HasCommitted()) { |
449 net::Error error = navigation_handle->GetNetErrorCode(); | 482 net::Error error = navigation_handle->GetNetErrorCode(); |
450 finished_nav->RecordProvisionalEvent( | 483 ProvisionalLoadEvent event = error == net::OK ? PROVISIONAL_LOAD_STOPPED |
451 error == net::OK ? PROVISIONAL_LOAD_STOPPED | |
452 : error == net::ERR_ABORTED ? PROVISIONAL_LOAD_ERR_ABORTED | 484 : error == net::ERR_ABORTED ? PROVISIONAL_LOAD_ERR_ABORTED |
453 : PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT); | 485 : PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT; |
486 finished_nav->RecordProvisionalEvent(event); | |
487 if (event != PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT) { | |
488 finished_nav->NotifyAbort(ABORT_OTHER, base::TimeTicks::Now()); | |
489 aborted_provisional_loads_.push_back(std::move(finished_nav)); | |
490 } | |
454 return; | 491 return; |
455 } | 492 } |
456 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_COMMITTED); | 493 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_COMMITTED); |
457 | 494 |
458 // Don't treat a same-page nav as a new page load. | 495 // Don't treat a same-page nav as a new page load. |
459 if (navigation_handle->IsSamePage()) | 496 if (navigation_handle->IsSamePage()) |
460 return; | 497 return; |
461 | 498 |
499 // Notify other loads that they may have been aborted by this committed load. | |
500 // Note that by using the committed navigation start as the abort cause, we | |
501 // lose data on provisional loads that were aborted by other provisional | |
502 // loads. Those will either be listed as ABORT_OTHER or as being aborted by | |
503 // this load. | |
504 NotifyAbortAllLoadsWithTimestamp( | |
505 AbortTypeForPageTransition(navigation_handle->GetPageTransition()), | |
506 navigation_handle->NavigationStart()); | |
507 | |
462 committed_load_ = finished_nav.Pass(); | 508 committed_load_ = finished_nav.Pass(); |
509 aborted_provisional_loads_.clear(); | |
463 | 510 |
464 const GURL& browser_url = web_contents()->GetLastCommittedURL(); | 511 const GURL& browser_url = web_contents()->GetLastCommittedURL(); |
465 const std::string& mime_type = web_contents()->GetContentsMimeType(); | 512 const std::string& mime_type = web_contents()->GetContentsMimeType(); |
466 DCHECK(!browser_url.is_empty()); | 513 DCHECK(!browser_url.is_empty()); |
467 DCHECK(!mime_type.empty()); | 514 DCHECK(!mime_type.empty()); |
468 committed_load_->set_renderer_tracked( | 515 committed_load_->set_renderer_tracked( |
469 IsRelevantNavigation(navigation_handle, browser_url, mime_type)); | 516 IsRelevantNavigation(navigation_handle, browser_url, mime_type)); |
470 | 517 |
471 committed_load_->Commit(navigation_handle); | 518 committed_load_->Commit(navigation_handle); |
472 } | 519 } |
473 | 520 |
521 void MetricsWebContentsObserver::NavigationStopped() { | |
522 NotifyAbortAllLoads(ABORT_STOP); | |
523 } | |
524 | |
474 void MetricsWebContentsObserver::DidRedirectNavigation( | 525 void MetricsWebContentsObserver::DidRedirectNavigation( |
475 content::NavigationHandle* navigation_handle) { | 526 content::NavigationHandle* navigation_handle) { |
476 if (!navigation_handle->IsInMainFrame()) | 527 if (!navigation_handle->IsInMainFrame()) |
477 return; | 528 return; |
478 auto it = provisional_loads_.find(navigation_handle); | 529 auto it = provisional_loads_.find(navigation_handle); |
479 if (it == provisional_loads_.end()) | 530 if (it == provisional_loads_.end()) |
480 return; | 531 return; |
481 it->second->Redirect(navigation_handle); | 532 it->second->Redirect(navigation_handle); |
482 } | 533 } |
483 | 534 |
(...skipping 13 matching lines...) Expand all Loading... | |
497 for (const auto& kv : provisional_loads_) { | 548 for (const auto& kv : provisional_loads_) { |
498 kv.second->WebContentsHidden(); | 549 kv.second->WebContentsHidden(); |
499 } | 550 } |
500 } | 551 } |
501 | 552 |
502 // This will occur when the process for the main RenderFrameHost exits, either | 553 // This will occur when the process for the main RenderFrameHost exits, either |
503 // normally or from a crash. We eagerly log data from the last committed load if | 554 // normally or from a crash. We eagerly log data from the last committed load if |
504 // we have one. | 555 // we have one. |
505 void MetricsWebContentsObserver::RenderProcessGone( | 556 void MetricsWebContentsObserver::RenderProcessGone( |
506 base::TerminationStatus status) { | 557 base::TerminationStatus status) { |
558 NotifyAbortAllLoads(ABORT_CLOSE); | |
507 committed_load_.reset(); | 559 committed_load_.reset(); |
560 provisional_loads_.clear(); | |
561 aborted_provisional_loads_.clear(); | |
562 } | |
563 | |
564 void MetricsWebContentsObserver::NotifyAbortAllLoads(UserAbortType abort_type) { | |
565 NotifyAbortAllLoadsWithTimestamp(abort_type, base::TimeTicks::Now()); | |
566 } | |
567 | |
568 void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp( | |
569 UserAbortType abort_type, | |
570 const base::TimeTicks& timestamp) { | |
571 if (committed_load_) | |
572 committed_load_->NotifyAbort(abort_type, timestamp); | |
573 for (const auto& kv : provisional_loads_) { | |
574 kv.second->NotifyAbort(abort_type, timestamp); | |
575 } | |
576 for (const auto& plt : aborted_provisional_loads_) { | |
577 plt->NotifyAbort(abort_type, timestamp); | |
578 } | |
508 } | 579 } |
509 | 580 |
510 void MetricsWebContentsObserver::OnTimingUpdated( | 581 void MetricsWebContentsObserver::OnTimingUpdated( |
511 content::RenderFrameHost* render_frame_host, | 582 content::RenderFrameHost* render_frame_host, |
512 const PageLoadTiming& timing) { | 583 const PageLoadTiming& timing) { |
513 bool error = false; | 584 bool error = false; |
514 if (!committed_load_ || !committed_load_->renderer_tracked()) { | 585 if (!committed_load_ || !committed_load_->renderer_tracked()) { |
515 RecordInternalError(ERR_IPC_WITH_NO_RELEVANT_LOAD); | 586 RecordInternalError(ERR_IPC_WITH_NO_RELEVANT_LOAD); |
516 error = true; | 587 error = true; |
517 } | 588 } |
(...skipping 18 matching lines...) Expand all Loading... | |
536 | 607 |
537 if (!committed_load_->UpdateTiming(timing)) { | 608 if (!committed_load_->UpdateTiming(timing)) { |
538 // If the page load tracker cannot update its timing, something is wrong | 609 // If the page load tracker cannot update its timing, something is wrong |
539 // with the IPC (it's from another load, or it's invalid in some other way). | 610 // with the IPC (it's from another load, or it's invalid in some other way). |
540 // We expect this to be a rare occurrence. | 611 // We expect this to be a rare occurrence. |
541 RecordInternalError(ERR_BAD_TIMING_IPC); | 612 RecordInternalError(ERR_BAD_TIMING_IPC); |
542 } | 613 } |
543 } | 614 } |
544 | 615 |
545 } // namespace page_load_metrics | 616 } // namespace page_load_metrics |
OLD | NEW |