Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(535)

Side by Side Diff: components/page_load_metrics/browser/metrics_web_contents_observer.cc

Issue 1984173002: Log First User Interaction in Page Load Metrics (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Plumbing RWH latency tracker instead of DidGetUserInteraction API Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698