Chromium Code Reviews| 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 <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
| 14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 15 #include "base/metrics/user_metrics.h" | 15 #include "base/metrics/user_metrics.h" |
| 16 #include "components/page_load_metrics/browser/page_load_metrics_util.h" | 16 #include "components/page_load_metrics/browser/page_load_metrics_util.h" |
| 17 #include "components/page_load_metrics/common/page_load_metrics_messages.h" | 17 #include "components/page_load_metrics/common/page_load_metrics_messages.h" |
| 18 #include "components/page_load_metrics/common/page_load_timing.h" | 18 #include "components/page_load_metrics/common/page_load_timing.h" |
| 19 #include "content/browser/renderer_host/render_view_host_impl.h" | |
|
Bryan McQuade
2016/05/25 21:32:29
My understanding is that you can't depend on conte
| |
| 19 #include "content/public/browser/browser_thread.h" | 20 #include "content/public/browser/browser_thread.h" |
| 20 #include "content/public/browser/navigation_details.h" | 21 #include "content/public/browser/navigation_details.h" |
| 21 #include "content/public/browser/navigation_handle.h" | 22 #include "content/public/browser/navigation_handle.h" |
| 22 #include "content/public/browser/render_frame_host.h" | 23 #include "content/public/browser/render_frame_host.h" |
| 23 #include "content/public/browser/web_contents.h" | 24 #include "content/public/browser/web_contents.h" |
| 24 #include "content/public/browser/web_contents_observer.h" | 25 #include "content/public/browser/web_contents_observer.h" |
| 25 #include "content/public/browser/web_contents_user_data.h" | 26 #include "content/public/browser/web_contents_user_data.h" |
| 26 #include "ipc/ipc_message.h" | 27 #include "ipc/ipc_message.h" |
| 27 #include "ipc/ipc_message_macros.h" | 28 #include "ipc/ipc_message_macros.h" |
| 28 #include "ui/base/page_transition_types.h" | 29 #include "ui/base/page_transition_types.h" |
| 29 | 30 |
| 30 DEFINE_WEB_CONTENTS_USER_DATA_KEY( | 31 DEFINE_WEB_CONTENTS_USER_DATA_KEY( |
| 31 page_load_metrics::MetricsWebContentsObserver); | 32 page_load_metrics::MetricsWebContentsObserver); |
| 32 | 33 |
| 34 class RenderViewHost; | |
| 35 | |
| 33 namespace page_load_metrics { | 36 namespace page_load_metrics { |
| 34 | 37 |
| 35 namespace internal { | 38 namespace internal { |
| 36 | 39 |
| 37 const char kErrorEvents[] = "PageLoad.Events.InternalError"; | 40 const char kErrorEvents[] = "PageLoad.Events.InternalError"; |
| 38 const char kAbortChainSizeReload[] = | 41 const char kAbortChainSizeReload[] = |
| 39 "PageLoad.Internal.ProvisionalAbortChainSize.Reload"; | 42 "PageLoad.Internal.ProvisionalAbortChainSize.Reload"; |
| 40 const char kAbortChainSizeForwardBack[] = | 43 const char kAbortChainSizeForwardBack[] = |
| 41 "PageLoad.Internal.ProvisionalAbortChainSize.ForwardBack"; | 44 "PageLoad.Internal.ProvisionalAbortChainSize.ForwardBack"; |
| 42 const char kAbortChainSizeNewNavigation[] = | 45 const char kAbortChainSizeNewNavigation[] = |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 observer->OnFailedProvisionalLoad(navigation_handle); | 361 observer->OnFailedProvisionalLoad(navigation_handle); |
| 359 } | 362 } |
| 360 } | 363 } |
| 361 | 364 |
| 362 void PageLoadTracker::Redirect(content::NavigationHandle* navigation_handle) { | 365 void PageLoadTracker::Redirect(content::NavigationHandle* navigation_handle) { |
| 363 for (const auto& observer : observers_) { | 366 for (const auto& observer : observers_) { |
| 364 observer->OnRedirect(navigation_handle); | 367 observer->OnRedirect(navigation_handle); |
| 365 } | 368 } |
| 366 } | 369 } |
| 367 | 370 |
| 371 void PageLoadTracker::OnInputEvent(const blink::WebInputEvent& event) { | |
| 372 // Only log the first user interaction in a given page load. | |
| 373 if (user_interaction_time_.is_null()) | |
| 374 user_interaction_time_ = base::TimeTicks::Now(); | |
| 375 | |
| 376 for (const auto& observer : observers_) { | |
| 377 observer->OnUserInput(event); | |
| 378 } | |
| 379 } | |
| 380 | |
| 368 bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, | 381 bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, |
| 369 const PageLoadMetadata& new_metadata) { | 382 const PageLoadMetadata& new_metadata) { |
| 370 // Throw away IPCs that are not relevant to the current navigation. | 383 // Throw away IPCs that are not relevant to the current navigation. |
| 371 // Two timing structures cannot refer to the same navigation if they indicate | 384 // Two timing structures cannot refer to the same navigation if they indicate |
| 372 // that a navigation started at different times, so a new timing struct with a | 385 // that a navigation started at different times, so a new timing struct with a |
| 373 // different start time from an earlier struct is considered invalid. | 386 // different start time from an earlier struct is considered invalid. |
| 374 bool valid_timing_descendent = | 387 bool valid_timing_descendent = |
| 375 timing_.navigation_start.is_null() || | 388 timing_.navigation_start.is_null() || |
| 376 timing_.navigation_start == new_timing.navigation_start; | 389 timing_.navigation_start == new_timing.navigation_start; |
| 377 // Ensure flags sent previously are still present in the new metadata fields. | 390 // Ensure flags sent previously are still present in the new metadata fields. |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 404 } | 417 } |
| 405 | 418 |
| 406 void PageLoadTracker::AddObserver( | 419 void PageLoadTracker::AddObserver( |
| 407 std::unique_ptr<PageLoadMetricsObserver> observer) { | 420 std::unique_ptr<PageLoadMetricsObserver> observer) { |
| 408 observers_.push_back(std::move(observer)); | 421 observers_.push_back(std::move(observer)); |
| 409 } | 422 } |
| 410 | 423 |
| 411 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { | 424 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { |
| 412 base::TimeDelta first_background_time; | 425 base::TimeDelta first_background_time; |
| 413 base::TimeDelta first_foreground_time; | 426 base::TimeDelta first_foreground_time; |
| 427 base::TimeDelta first_user_interaction_time; | |
| 414 base::TimeDelta time_to_abort; | 428 base::TimeDelta time_to_abort; |
| 415 base::TimeDelta time_to_commit; | 429 base::TimeDelta time_to_commit; |
| 416 if (!background_time_.is_null()) | 430 if (!background_time_.is_null()) |
| 417 first_background_time = background_time_ - navigation_start_; | 431 first_background_time = background_time_ - navigation_start_; |
| 418 if (!foreground_time_.is_null()) | 432 if (!foreground_time_.is_null()) |
| 419 first_foreground_time = foreground_time_ - navigation_start_; | 433 first_foreground_time = foreground_time_ - navigation_start_; |
| 434 if (!user_interaction_time_.is_null()) | |
| 435 first_user_interaction_time = user_interaction_time_ - navigation_start_; | |
| 420 if (abort_type_ != ABORT_NONE) { | 436 if (abort_type_ != ABORT_NONE) { |
| 421 DCHECK_GT(abort_time_, navigation_start_); | 437 DCHECK_GT(abort_time_, navigation_start_); |
| 422 time_to_abort = abort_time_ - navigation_start_; | 438 time_to_abort = abort_time_ - navigation_start_; |
| 423 } else { | 439 } else { |
| 424 DCHECK(abort_time_.is_null()); | 440 DCHECK(abort_time_.is_null()); |
| 425 } | 441 } |
| 426 | 442 |
| 427 if (!commit_time_.is_null()) { | 443 if (!commit_time_.is_null()) { |
| 428 DCHECK_GT(commit_time_, navigation_start_); | 444 DCHECK_GT(commit_time_, navigation_start_); |
| 429 time_to_commit = commit_time_ - navigation_start_; | 445 time_to_commit = commit_time_ - navigation_start_; |
| 430 } else { | 446 } else { |
| 431 DCHECK(commit_time_.is_null()); | 447 DCHECK(commit_time_.is_null()); |
| 432 } | 448 } |
| 433 return PageLoadExtraInfo( | 449 return PageLoadExtraInfo( |
| 434 first_background_time, first_foreground_time, started_in_foreground_, | 450 first_background_time, first_foreground_time, first_user_interaction_time, |
| 435 commit_time_.is_null() ? GURL() : url_, time_to_commit, abort_type_, | 451 started_in_foreground_, commit_time_.is_null() ? GURL() : url_, |
| 436 time_to_abort, metadata_); | 452 time_to_commit, abort_type_, time_to_abort, metadata_); |
| 437 } | 453 } |
| 438 | 454 |
| 439 void PageLoadTracker::NotifyAbort(UserAbortType abort_type, | 455 void PageLoadTracker::NotifyAbort(UserAbortType abort_type, |
| 440 base::TimeTicks timestamp) { | 456 base::TimeTicks timestamp) { |
| 441 DCHECK_NE(abort_type, ABORT_NONE); | 457 DCHECK_NE(abort_type, ABORT_NONE); |
| 442 // Use UpdateAbort to update an already notified PageLoadTracker. | 458 // Use UpdateAbort to update an already notified PageLoadTracker. |
| 443 if (abort_type_ != ABORT_NONE) | 459 if (abort_type_ != ABORT_NONE) |
| 444 return; | 460 return; |
| 445 | 461 |
| 446 UpdateAbortInternal(abort_type, timestamp); | 462 UpdateAbortInternal(abort_type, timestamp); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 507 content::WebContents* web_contents, | 523 content::WebContents* web_contents, |
| 508 std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface) { | 524 std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface) { |
| 509 DCHECK(web_contents); | 525 DCHECK(web_contents); |
| 510 | 526 |
| 511 MetricsWebContentsObserver* metrics = FromWebContents(web_contents); | 527 MetricsWebContentsObserver* metrics = FromWebContents(web_contents); |
| 512 if (!metrics) { | 528 if (!metrics) { |
| 513 metrics = new MetricsWebContentsObserver(web_contents, | 529 metrics = new MetricsWebContentsObserver(web_contents, |
| 514 std::move(embedder_interface)); | 530 std::move(embedder_interface)); |
| 515 web_contents->SetUserData(UserDataKey(), metrics); | 531 web_contents->SetUserData(UserDataKey(), metrics); |
| 516 } | 532 } |
| 533 | |
| 534 content::RenderWidgetHostImpl* rwhi = content::RenderWidgetHostImpl::From( | |
|
Bryan McQuade
2016/05/25 20:47:04
since we're unlistening in the destructor, let's l
| |
| 535 metrics->web_contents()->GetRenderViewHost()->GetWidget()); | |
| 536 rwhi->latency_tracker()->AddInputEventCallback(base::Bind( | |
| 537 &MetricsWebContentsObserver::OnInputEvent, base::Unretained(metrics))); | |
| 538 | |
| 517 return metrics; | 539 return metrics; |
| 518 } | 540 } |
| 519 | 541 |
| 520 MetricsWebContentsObserver::~MetricsWebContentsObserver() { | 542 MetricsWebContentsObserver::~MetricsWebContentsObserver() { |
| 521 NotifyAbortAllLoads(ABORT_CLOSE); | 543 content::RenderWidgetHostImpl* rwhi = content::RenderWidgetHostImpl::From( |
| 544 web_contents()->GetRenderViewHost()->GetWidget()); | |
|
Bryan McQuade
2016/05/25 19:02:47
My understanding is that a RenderViewHost's lifeti
Bryan McQuade
2016/05/25 20:47:04
I think you can address this issue by implementing
| |
| 545 rwhi->latency_tracker()->RemoveInputEventCallback(base::Bind( | |
| 546 &MetricsWebContentsObserver::OnInputEvent, base::Unretained(this))); | |
| 522 } | 547 } |
| 523 | 548 |
| 524 bool MetricsWebContentsObserver::OnMessageReceived( | 549 bool MetricsWebContentsObserver::OnMessageReceived( |
| 525 const IPC::Message& message, | 550 const IPC::Message& message, |
| 526 content::RenderFrameHost* render_frame_host) { | 551 content::RenderFrameHost* render_frame_host) { |
| 527 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 552 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 528 bool handled = true; | 553 bool handled = true; |
| 529 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message, | 554 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message, |
| 530 render_frame_host) | 555 render_frame_host) |
| 531 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) | 556 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 649 committed_load_->set_renderer_tracked( | 674 committed_load_->set_renderer_tracked( |
| 650 IsRelevantNavigation(navigation_handle, browser_url, mime_type)); | 675 IsRelevantNavigation(navigation_handle, browser_url, mime_type)); |
| 651 | 676 |
| 652 committed_load_->Commit(navigation_handle); | 677 committed_load_->Commit(navigation_handle); |
| 653 } | 678 } |
| 654 | 679 |
| 655 void MetricsWebContentsObserver::NavigationStopped() { | 680 void MetricsWebContentsObserver::NavigationStopped() { |
| 656 NotifyAbortAllLoads(ABORT_STOP); | 681 NotifyAbortAllLoads(ABORT_STOP); |
| 657 } | 682 } |
| 658 | 683 |
| 684 bool MetricsWebContentsObserver::OnInputEvent( | |
| 685 const blink::WebInputEvent& event) { | |
| 686 // ignore browser navigation or reload which comes with type Undefined | |
|
tdresser
2016/05/24 14:28:38
Capitalization and end with .
| |
| 687 if (event.type != blink::WebInputEvent::Type::Undefined) { | |
| 688 if (!committed_load_) { | |
| 689 RecordInternalError(ERR_USER_INTERACTION_WITH_NO_RELEVANT_LOAD); | |
| 690 return false; | |
| 691 } | |
| 692 committed_load_->OnInputEvent(event); | |
| 693 return true; | |
| 694 } | |
| 695 | |
| 696 return false; | |
| 697 } | |
| 698 | |
| 659 void MetricsWebContentsObserver::DidRedirectNavigation( | 699 void MetricsWebContentsObserver::DidRedirectNavigation( |
| 660 content::NavigationHandle* navigation_handle) { | 700 content::NavigationHandle* navigation_handle) { |
| 661 if (!navigation_handle->IsInMainFrame()) | 701 if (!navigation_handle->IsInMainFrame()) |
| 662 return; | 702 return; |
| 663 auto it = provisional_loads_.find(navigation_handle); | 703 auto it = provisional_loads_.find(navigation_handle); |
| 664 if (it == provisional_loads_.end()) | 704 if (it == provisional_loads_.end()) |
| 665 return; | 705 return; |
| 666 it->second->Redirect(navigation_handle); | 706 it->second->Redirect(navigation_handle); |
| 667 } | 707 } |
| 668 | 708 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 781 | 821 |
| 782 if (!committed_load_->UpdateTiming(timing, metadata)) { | 822 if (!committed_load_->UpdateTiming(timing, metadata)) { |
| 783 // If the page load tracker cannot update its timing, something is wrong | 823 // If the page load tracker cannot update its timing, something is wrong |
| 784 // with the IPC (it's from another load, or it's invalid in some other way). | 824 // with the IPC (it's from another load, or it's invalid in some other way). |
| 785 // We expect this to be a rare occurrence. | 825 // We expect this to be a rare occurrence. |
| 786 RecordInternalError(ERR_BAD_TIMING_IPC); | 826 RecordInternalError(ERR_BAD_TIMING_IPC); |
| 787 } | 827 } |
| 788 } | 828 } |
| 789 | 829 |
| 790 } // namespace page_load_metrics | 830 } // namespace page_load_metrics |
| OLD | NEW |