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 |