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 "chrome/browser/page_load_metrics/metrics_web_contents_observer.h" | 5 #include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <ostream> | 8 #include <ostream> |
9 #include <string> | 9 #include <string> |
10 #include <utility> | 10 #include <utility> |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 if (!metrics) { | 75 if (!metrics) { |
76 metrics = new MetricsWebContentsObserver(web_contents, | 76 metrics = new MetricsWebContentsObserver(web_contents, |
77 std::move(embedder_interface)); | 77 std::move(embedder_interface)); |
78 web_contents->SetUserData(UserDataKey(), metrics); | 78 web_contents->SetUserData(UserDataKey(), metrics); |
79 } | 79 } |
80 return metrics; | 80 return metrics; |
81 } | 81 } |
82 | 82 |
83 MetricsWebContentsObserver::~MetricsWebContentsObserver() { | 83 MetricsWebContentsObserver::~MetricsWebContentsObserver() { |
84 // TODO(csharrison): Use a more user-initiated signal for CLOSE. | 84 // TODO(csharrison): Use a more user-initiated signal for CLOSE. |
85 NotifyAbortAllLoads(ABORT_CLOSE, UserInitiatedInfo::NotUserInitiated()); | 85 NotifyPageEndAllLoads(END_CLOSE, UserInitiatedInfo::NotUserInitiated()); |
86 } | 86 } |
87 | 87 |
88 void MetricsWebContentsObserver::RegisterInputEventObserver( | 88 void MetricsWebContentsObserver::RegisterInputEventObserver( |
89 content::RenderViewHost* host) { | 89 content::RenderViewHost* host) { |
90 if (host != nullptr) | 90 if (host != nullptr) |
91 host->GetWidget()->AddInputEventObserver(this); | 91 host->GetWidget()->AddInputEventObserver(this); |
92 } | 92 } |
93 | 93 |
94 void MetricsWebContentsObserver::UnregisterInputEventObserver( | 94 void MetricsWebContentsObserver::UnregisterInputEventObserver( |
95 content::RenderViewHost* host) { | 95 content::RenderViewHost* host) { |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 | 286 |
287 if (navigation_handle->HasCommitted()) { | 287 if (navigation_handle->HasCommitted()) { |
288 UserInitiatedInfo user_initiated_info = | 288 UserInitiatedInfo user_initiated_info = |
289 finished_nav | 289 finished_nav |
290 ? finished_nav->user_initiated_info() | 290 ? finished_nav->user_initiated_info() |
291 : CreateUserInitiatedInfo(navigation_handle, committed_load_.get()); | 291 : CreateUserInitiatedInfo(navigation_handle, committed_load_.get()); |
292 | 292 |
293 // Notify other loads that they may have been aborted by this committed | 293 // Notify other loads that they may have been aborted by this committed |
294 // load. is_certainly_browser_timestamp is set to false because | 294 // load. is_certainly_browser_timestamp is set to false because |
295 // NavigationStart() could be set in either the renderer or browser process. | 295 // NavigationStart() could be set in either the renderer or browser process. |
296 NotifyAbortAllLoadsWithTimestamp( | 296 NotifyPageEndAllLoadsWithTimestamp( |
297 AbortTypeForPageTransition(navigation_handle->GetPageTransition()), | 297 EndReasonForPageTransition(navigation_handle->GetPageTransition()), |
298 user_initiated_info, navigation_handle->NavigationStart(), false); | 298 user_initiated_info, navigation_handle->NavigationStart(), false); |
299 | 299 |
300 if (should_track) { | 300 if (should_track) { |
301 HandleCommittedNavigationForTrackedLoad(navigation_handle, | 301 HandleCommittedNavigationForTrackedLoad(navigation_handle, |
302 std::move(finished_nav)); | 302 std::move(finished_nav)); |
303 } else { | 303 } else { |
304 committed_load_.reset(); | 304 committed_load_.reset(); |
305 } | 305 } |
306 } else if (should_track) { | 306 } else if (should_track) { |
307 HandleFailedNavigationForTrackedLoad(navigation_handle, | 307 HandleFailedNavigationForTrackedLoad(navigation_handle, |
308 std::move(finished_nav)); | 308 std::move(finished_nav)); |
309 } | 309 } |
310 } | 310 } |
311 | 311 |
312 // Handle a pre-commit error. Navigations that result in an error page will be | 312 // Handle a pre-commit error. Navigations that result in an error page will be |
313 // ignored. | 313 // ignored. |
314 void MetricsWebContentsObserver::HandleFailedNavigationForTrackedLoad( | 314 void MetricsWebContentsObserver::HandleFailedNavigationForTrackedLoad( |
315 content::NavigationHandle* navigation_handle, | 315 content::NavigationHandle* navigation_handle, |
316 std::unique_ptr<PageLoadTracker> tracker) { | 316 std::unique_ptr<PageLoadTracker> tracker) { |
317 tracker->FailedProvisionalLoad(navigation_handle); | 317 const base::TimeTicks now = base::TimeTicks::Now(); |
| 318 tracker->FailedProvisionalLoad(navigation_handle, now); |
318 | 319 |
319 net::Error error = navigation_handle->GetNetErrorCode(); | 320 const net::Error error = navigation_handle->GetNetErrorCode(); |
320 | 321 |
321 // net::OK: This case occurs when the NavigationHandle finishes and reports | 322 // net::OK: This case occurs when the NavigationHandle finishes and reports |
322 // !HasCommitted(), but reports no net::Error. This should not occur | 323 // !HasCommitted(), but reports no net::Error. This should not occur |
323 // pre-PlzNavigate, but afterwards it should represent the navigation stopped | 324 // pre-PlzNavigate, but afterwards it should represent the navigation stopped |
324 // by the user before it was ready to commit. | 325 // by the user before it was ready to commit. |
325 // net::ERR_ABORTED: An aborted provisional load has error | 326 // net::ERR_ABORTED: An aborted provisional load has error net::ERR_ABORTED. |
326 // net::ERR_ABORTED. | 327 const bool is_aborted_provisional_load = |
327 if ((error == net::OK) || (error == net::ERR_ABORTED)) { | 328 error == net::OK || error == net::ERR_ABORTED; |
328 tracker->NotifyAbort(ABORT_OTHER, UserInitiatedInfo::NotUserInitiated(), | 329 |
329 base::TimeTicks::Now(), true); | 330 // If is_aborted_provisional_load, the page end reason is not yet known, and |
| 331 // will be updated as additional information is available from subsequent |
| 332 // navigations. |
| 333 tracker->NotifyPageEnd( |
| 334 is_aborted_provisional_load ? END_OTHER : END_PROVISIONAL_LOAD_FAILED, |
| 335 UserInitiatedInfo::NotUserInitiated(), now, true); |
| 336 |
| 337 if (is_aborted_provisional_load) |
330 aborted_provisional_loads_.push_back(std::move(tracker)); | 338 aborted_provisional_loads_.push_back(std::move(tracker)); |
331 } | |
332 } | 339 } |
333 | 340 |
334 void MetricsWebContentsObserver::HandleCommittedNavigationForTrackedLoad( | 341 void MetricsWebContentsObserver::HandleCommittedNavigationForTrackedLoad( |
335 content::NavigationHandle* navigation_handle, | 342 content::NavigationHandle* navigation_handle, |
336 std::unique_ptr<PageLoadTracker> tracker) { | 343 std::unique_ptr<PageLoadTracker> tracker) { |
337 if (!IsNavigationUserInitiated(navigation_handle) && | 344 if (!IsNavigationUserInitiated(navigation_handle) && |
338 (navigation_handle->GetPageTransition() & | 345 (navigation_handle->GetPageTransition() & |
339 ui::PAGE_TRANSITION_CLIENT_REDIRECT) != 0 && | 346 ui::PAGE_TRANSITION_CLIENT_REDIRECT) != 0 && |
340 committed_load_) { | 347 committed_load_) { |
341 // TODO(bmcquade): consider carrying the user_gesture bit forward to the | 348 // TODO(bmcquade): consider carrying the user_gesture bit forward to the |
342 // redirected navigation. | 349 // redirected navigation. |
343 committed_load_->NotifyClientRedirectTo(*tracker); | 350 committed_load_->NotifyClientRedirectTo(*tracker); |
344 } | 351 } |
345 | 352 |
346 committed_load_ = std::move(tracker); | 353 committed_load_ = std::move(tracker); |
347 committed_load_->Commit(navigation_handle); | 354 committed_load_->Commit(navigation_handle); |
348 DCHECK(committed_load_->did_commit()); | 355 DCHECK(committed_load_->did_commit()); |
349 } | 356 } |
350 | 357 |
351 void MetricsWebContentsObserver::NavigationStopped() { | 358 void MetricsWebContentsObserver::NavigationStopped() { |
352 // TODO(csharrison): Use a more user-initiated signal for STOP. | 359 // TODO(csharrison): Use a more user-initiated signal for STOP. |
353 NotifyAbortAllLoads(ABORT_STOP, UserInitiatedInfo::NotUserInitiated()); | 360 NotifyPageEndAllLoads(END_STOP, UserInitiatedInfo::NotUserInitiated()); |
354 } | 361 } |
355 | 362 |
356 void MetricsWebContentsObserver::OnInputEvent( | 363 void MetricsWebContentsObserver::OnInputEvent( |
357 const blink::WebInputEvent& event) { | 364 const blink::WebInputEvent& event) { |
358 // Ignore browser navigation or reload which comes with type Undefined. | 365 // Ignore browser navigation or reload which comes with type Undefined. |
359 if (event.type() == blink::WebInputEvent::Type::Undefined) | 366 if (event.type() == blink::WebInputEvent::Type::Undefined) |
360 return; | 367 return; |
361 | 368 |
362 if (committed_load_) | 369 if (committed_load_) |
363 committed_load_->OnInputEvent(event); | 370 committed_load_->OnInputEvent(event); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 in_foreground_ = false; | 414 in_foreground_ = false; |
408 if (committed_load_) | 415 if (committed_load_) |
409 committed_load_->WebContentsHidden(); | 416 committed_load_->WebContentsHidden(); |
410 for (const auto& kv : provisional_loads_) { | 417 for (const auto& kv : provisional_loads_) { |
411 kv.second->WebContentsHidden(); | 418 kv.second->WebContentsHidden(); |
412 } | 419 } |
413 } | 420 } |
414 | 421 |
415 // This will occur when the process for the main RenderFrameHost exits, either | 422 // This will occur when the process for the main RenderFrameHost exits, either |
416 // normally or from a crash. We eagerly log data from the last committed load if | 423 // normally or from a crash. We eagerly log data from the last committed load if |
417 // we have one. Don't notify aborts here because this is probably not user | 424 // we have one. |
418 // initiated. If it is (e.g. browser shutdown), other code paths will take care | |
419 // of notifying. | |
420 void MetricsWebContentsObserver::RenderProcessGone( | 425 void MetricsWebContentsObserver::RenderProcessGone( |
421 base::TerminationStatus status) { | 426 base::TerminationStatus status) { |
422 // Other code paths will be run for normal renderer shutdown. Note that we | 427 // Other code paths will be run for normal renderer shutdown. Note that we |
423 // sometimes get the STILL_RUNNING value on fast shutdown. | 428 // sometimes get the STILL_RUNNING value on fast shutdown. |
424 if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION || | 429 if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION || |
425 status == base::TERMINATION_STATUS_STILL_RUNNING) { | 430 status == base::TERMINATION_STATUS_STILL_RUNNING) { |
426 return; | 431 return; |
427 } | 432 } |
428 | 433 |
| 434 // RenderProcessGone is associated with the render frame host for the |
| 435 // currently committed load. We don't know if the pending navs or aborted |
| 436 // pending navs are associated w/ the render process that died, so we can't be |
| 437 // sure the info should propagate to them. |
| 438 if (committed_load_) { |
| 439 committed_load_->NotifyPageEnd(END_RENDER_PROCESS_GONE, |
| 440 UserInitiatedInfo::NotUserInitiated(), |
| 441 base::TimeTicks::Now(), true); |
| 442 } |
| 443 |
429 // If this is a crash, eagerly log the aborted provisional loads and the | 444 // If this is a crash, eagerly log the aborted provisional loads and the |
430 // committed load. |provisional_loads_| don't need to be destroyed here | 445 // committed load. |provisional_loads_| don't need to be destroyed here |
431 // because their lifetime is tied to the NavigationHandle. | 446 // because their lifetime is tied to the NavigationHandle. |
432 committed_load_.reset(); | 447 committed_load_.reset(); |
433 aborted_provisional_loads_.clear(); | 448 aborted_provisional_loads_.clear(); |
434 } | 449 } |
435 | 450 |
436 void MetricsWebContentsObserver::NotifyAbortAllLoads( | 451 void MetricsWebContentsObserver::NotifyPageEndAllLoads( |
437 UserAbortType abort_type, | 452 PageEndReason page_end_reason, |
438 UserInitiatedInfo user_initiated_info) { | 453 UserInitiatedInfo user_initiated_info) { |
439 NotifyAbortAllLoadsWithTimestamp(abort_type, user_initiated_info, | 454 NotifyPageEndAllLoadsWithTimestamp(page_end_reason, user_initiated_info, |
440 base::TimeTicks::Now(), true); | 455 base::TimeTicks::Now(), true); |
441 } | 456 } |
442 | 457 |
443 void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp( | 458 void MetricsWebContentsObserver::NotifyPageEndAllLoadsWithTimestamp( |
444 UserAbortType abort_type, | 459 PageEndReason page_end_reason, |
445 UserInitiatedInfo user_initiated_info, | 460 UserInitiatedInfo user_initiated_info, |
446 base::TimeTicks timestamp, | 461 base::TimeTicks timestamp, |
447 bool is_certainly_browser_timestamp) { | 462 bool is_certainly_browser_timestamp) { |
448 if (committed_load_) { | 463 if (committed_load_) { |
449 committed_load_->NotifyAbort(abort_type, user_initiated_info, timestamp, | 464 committed_load_->NotifyPageEnd(page_end_reason, user_initiated_info, |
450 is_certainly_browser_timestamp); | 465 timestamp, is_certainly_browser_timestamp); |
451 } | 466 } |
452 for (const auto& kv : provisional_loads_) { | 467 for (const auto& kv : provisional_loads_) { |
453 kv.second->NotifyAbort(abort_type, user_initiated_info, timestamp, | 468 kv.second->NotifyPageEnd(page_end_reason, user_initiated_info, timestamp, |
454 is_certainly_browser_timestamp); | 469 is_certainly_browser_timestamp); |
455 } | 470 } |
456 for (const auto& tracker : aborted_provisional_loads_) { | 471 for (const auto& tracker : aborted_provisional_loads_) { |
457 if (tracker->IsLikelyProvisionalAbort(timestamp)) { | 472 if (tracker->IsLikelyProvisionalAbort(timestamp)) { |
458 tracker->UpdateAbort(abort_type, user_initiated_info, timestamp, | 473 tracker->UpdatePageEnd(page_end_reason, user_initiated_info, timestamp, |
459 is_certainly_browser_timestamp); | 474 is_certainly_browser_timestamp); |
460 } | 475 } |
461 } | 476 } |
462 aborted_provisional_loads_.clear(); | 477 aborted_provisional_loads_.clear(); |
463 } | 478 } |
464 | 479 |
465 std::unique_ptr<PageLoadTracker> | 480 std::unique_ptr<PageLoadTracker> |
466 MetricsWebContentsObserver::NotifyAbortedProvisionalLoadsNewNavigation( | 481 MetricsWebContentsObserver::NotifyAbortedProvisionalLoadsNewNavigation( |
467 content::NavigationHandle* new_navigation, | 482 content::NavigationHandle* new_navigation, |
468 UserInitiatedInfo user_initiated_info) { | 483 UserInitiatedInfo user_initiated_info) { |
469 // If there are multiple aborted loads that can be attributed to this one, | 484 // If there are multiple aborted loads that can be attributed to this one, |
470 // just count the latest one for simplicity. Other loads will fall into the | 485 // just count the latest one for simplicity. Other loads will fall into the |
471 // OTHER bucket, though there shouldn't be very many. | 486 // OTHER bucket, though there shouldn't be very many. |
472 if (aborted_provisional_loads_.size() == 0) | 487 if (aborted_provisional_loads_.size() == 0) |
473 return nullptr; | 488 return nullptr; |
474 if (aborted_provisional_loads_.size() > 1) | 489 if (aborted_provisional_loads_.size() > 1) |
475 RecordInternalError(ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS); | 490 RecordInternalError(ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS); |
476 | 491 |
477 std::unique_ptr<PageLoadTracker> last_aborted_load = | 492 std::unique_ptr<PageLoadTracker> last_aborted_load = |
478 std::move(aborted_provisional_loads_.back()); | 493 std::move(aborted_provisional_loads_.back()); |
479 aborted_provisional_loads_.pop_back(); | 494 aborted_provisional_loads_.pop_back(); |
480 | 495 |
481 base::TimeTicks timestamp = new_navigation->NavigationStart(); | 496 base::TimeTicks timestamp = new_navigation->NavigationStart(); |
482 if (last_aborted_load->IsLikelyProvisionalAbort(timestamp)) { | 497 if (last_aborted_load->IsLikelyProvisionalAbort(timestamp)) { |
483 last_aborted_load->UpdateAbort( | 498 last_aborted_load->UpdatePageEnd( |
484 AbortTypeForPageTransition(new_navigation->GetPageTransition()), | 499 EndReasonForPageTransition(new_navigation->GetPageTransition()), |
485 user_initiated_info, timestamp, false); | 500 user_initiated_info, timestamp, false); |
486 } | 501 } |
487 | 502 |
488 aborted_provisional_loads_.clear(); | 503 aborted_provisional_loads_.clear(); |
489 return last_aborted_load; | 504 return last_aborted_load; |
490 } | 505 } |
491 | 506 |
492 void MetricsWebContentsObserver::OnTimingUpdated( | 507 void MetricsWebContentsObserver::OnTimingUpdated( |
493 content::RenderFrameHost* render_frame_host, | 508 content::RenderFrameHost* render_frame_host, |
494 const PageLoadTiming& timing, | 509 const PageLoadTiming& timing, |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 content::NavigationHandle* navigation_handle) const { | 545 content::NavigationHandle* navigation_handle) const { |
531 DCHECK(navigation_handle->IsInMainFrame()); | 546 DCHECK(navigation_handle->IsInMainFrame()); |
532 DCHECK(!navigation_handle->HasCommitted() || | 547 DCHECK(!navigation_handle->HasCommitted() || |
533 !navigation_handle->IsSamePage()); | 548 !navigation_handle->IsSamePage()); |
534 | 549 |
535 return BrowserPageTrackDecider(embedder_interface_.get(), web_contents(), | 550 return BrowserPageTrackDecider(embedder_interface_.get(), web_contents(), |
536 navigation_handle).ShouldTrack(); | 551 navigation_handle).ShouldTrack(); |
537 } | 552 } |
538 | 553 |
539 } // namespace page_load_metrics | 554 } // namespace page_load_metrics |
OLD | NEW |