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

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

Issue 2132603002: [page_load_metrics] Add a NavigationThrottle for richer abort metrics (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: bmcquade@ first review Created 4 years, 5 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 <ostream> 8 #include <ostream>
9 #include <string> 9 #include <string>
10 #include <utility> 10 #include <utility>
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 started_in_foreground_); 271 started_in_foreground_);
272 } 272 }
273 } 273 }
274 274
275 PageLoadTracker::~PageLoadTracker() { 275 PageLoadTracker::~PageLoadTracker() {
276 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); 276 const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
277 277
278 if (info.time_to_commit && renderer_tracked() && timing_.IsEmpty()) { 278 if (info.time_to_commit && renderer_tracked() && timing_.IsEmpty()) {
279 RecordInternalError(ERR_NO_IPCS_RECEIVED); 279 RecordInternalError(ERR_NO_IPCS_RECEIVED);
280 } 280 }
281 // Recall that trackers that are given ABORT_UNKNOWN_NAVIGATION have their 281
282 // chain length added to the next navigation. Take care not to double count 282 // Don't include any aborts that resulted in a new navigation, as the chain
283 // them. Also do not double count committed loads, which call this already. 283 // length will be included in the aborter PageLoadTracker.
284 if (commit_time_.is_null() && abort_type_ != ABORT_UNKNOWN_NAVIGATION) 284 if (commit_time_.is_null() && abort_type_ != ABORT_UNKNOWN_NAVIGATION &&
285 abort_type_ != ABORT_RELOAD && abort_type_ != ABORT_FORWARD_BACK &&
286 abort_type_ != ABORT_NEW_NAVIGATION) {
285 LogAbortChainHistograms(nullptr); 287 LogAbortChainHistograms(nullptr);
288 }
286 289
287 for (const auto& observer : observers_) { 290 for (const auto& observer : observers_) {
288 observer->OnComplete(timing_, info); 291 observer->OnComplete(timing_, info);
289 } 292 }
290 } 293 }
291 294
292 void PageLoadTracker::LogAbortChainHistograms( 295 void PageLoadTracker::LogAbortChainHistograms(
293 content::NavigationHandle* final_navigation) { 296 content::NavigationHandle* final_navigation) {
294 if (aborted_chain_size_ == 0) 297 if (aborted_chain_size_ == 0)
295 return; 298 return;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 LogAbortChainHistograms(navigation_handle); 379 LogAbortChainHistograms(navigation_handle);
377 } 380 }
378 381
379 void PageLoadTracker::FailedProvisionalLoad( 382 void PageLoadTracker::FailedProvisionalLoad(
380 content::NavigationHandle* navigation_handle) { 383 content::NavigationHandle* navigation_handle) {
381 for (const auto& observer : observers_) { 384 for (const auto& observer : observers_) {
382 observer->OnFailedProvisionalLoad(navigation_handle); 385 observer->OnFailedProvisionalLoad(navigation_handle);
383 } 386 }
384 } 387 }
385 388
389 // TODO(csharrison): We can get an approximation of whether the abort is user
390 // initiated or not from the NavigationHandle at this point.
391 void PageLoadTracker::WillStartNavigationRequest(
392 content::NavigationHandle* navigation_handle) {
393 page_transition_ = navigation_handle->GetPageTransition();
394 }
395
386 void PageLoadTracker::Redirect(content::NavigationHandle* navigation_handle) { 396 void PageLoadTracker::Redirect(content::NavigationHandle* navigation_handle) {
387 for (const auto& observer : observers_) { 397 for (const auto& observer : observers_) {
388 observer->OnRedirect(navigation_handle); 398 observer->OnRedirect(navigation_handle);
389 } 399 }
390 } 400 }
391 401
392 void PageLoadTracker::OnInputEvent(const blink::WebInputEvent& event) { 402 void PageLoadTracker::OnInputEvent(const blink::WebInputEvent& event) {
393 for (const auto& observer : observers_) { 403 for (const auto& observer : observers_) {
394 observer->OnUserInput(event); 404 observer->OnUserInput(event);
395 } 405 }
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 return; 534 return;
525 535
526 UpdateAbortInternal(abort_type, timestamp, is_certainly_browser_timestamp); 536 UpdateAbortInternal(abort_type, timestamp, is_certainly_browser_timestamp);
527 } 537 }
528 538
529 void PageLoadTracker::UpdateAbort(UserAbortType abort_type, 539 void PageLoadTracker::UpdateAbort(UserAbortType abort_type,
530 base::TimeTicks timestamp, 540 base::TimeTicks timestamp,
531 bool is_certainly_browser_timestamp) { 541 bool is_certainly_browser_timestamp) {
532 DCHECK_NE(abort_type, ABORT_NONE); 542 DCHECK_NE(abort_type, ABORT_NONE);
533 DCHECK_NE(abort_type, ABORT_OTHER); 543 DCHECK_NE(abort_type, ABORT_OTHER);
534 DCHECK_EQ(abort_type_, ABORT_OTHER); 544 DCHECK(abort_type_ == ABORT_OTHER || abort_type_ == ABORT_UNKNOWN_NAVIGATION)
545 << "UpdateAbort called with abort_type_ = " << abort_type_;
535 546
536 // For some aborts (e.g. navigations), the initiated timestamp can be earlier 547 // For some aborts (e.g. navigations), the initiated timestamp can be earlier
537 // than the timestamp that aborted the load. Taking the minimum gives the 548 // than the timestamp that aborted the load. Taking the minimum gives the
538 // closest user initiated time known. 549 // closest user initiated time known.
539 UpdateAbortInternal(abort_type, std::min(abort_time_, timestamp), 550 UpdateAbortInternal(abort_type, std::min(abort_time_, timestamp),
540 is_certainly_browser_timestamp); 551 is_certainly_browser_timestamp);
541 } 552 }
542 553
543 bool PageLoadTracker::IsLikelyProvisionalAbort( 554 bool PageLoadTracker::WasAbortedRecently(base::TimeTicks abort_cause_time) {
544 base::TimeTicks abort_cause_time) {
545 // Note that |abort_cause_time - abort_time| can be negative. 555 // Note that |abort_cause_time - abort_time| can be negative.
546 return abort_type_ == ABORT_OTHER && 556 return (abort_cause_time - abort_time_).InMilliseconds() < 100;
547 (abort_cause_time - abort_time_).InMilliseconds() < 100;
548 } 557 }
549 558
550 bool PageLoadTracker::MatchesOriginalNavigation( 559 bool PageLoadTracker::MatchesOriginalNavigation(
551 content::NavigationHandle* navigation_handle) { 560 content::NavigationHandle* navigation_handle) {
552 // Neither navigation should have committed. 561 // Neither navigation should have committed.
553 DCHECK(!navigation_handle->HasCommitted()); 562 DCHECK(!navigation_handle->HasCommitted());
554 DCHECK(commit_time_.is_null()); 563 DCHECK(commit_time_.is_null());
555 return navigation_handle->GetURL() == url_; 564 return navigation_handle->GetURL() == url_;
556 } 565 }
557 566
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
635 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 644 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
636 bool handled = true; 645 bool handled = true;
637 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message, 646 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message,
638 render_frame_host) 647 render_frame_host)
639 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) 648 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated)
640 IPC_MESSAGE_UNHANDLED(handled = false) 649 IPC_MESSAGE_UNHANDLED(handled = false)
641 IPC_END_MESSAGE_MAP() 650 IPC_END_MESSAGE_MAP()
642 return handled; 651 return handled;
643 } 652 }
644 653
654 // TODO(csharrison): The only reason DidStartNavigation is needed is for unit
655 // tests. Otherwise all this logic can go in WillStartNavigationRequest.
645 void MetricsWebContentsObserver::DidStartNavigation( 656 void MetricsWebContentsObserver::DidStartNavigation(
646 content::NavigationHandle* navigation_handle) { 657 content::NavigationHandle* navigation_handle) {
647 if (!navigation_handle->IsInMainFrame()) 658 if (!navigation_handle->IsInMainFrame())
648 return; 659 return;
649 if (embedder_interface_->IsPrerendering(web_contents())) 660 if (embedder_interface_->IsPrerendering(web_contents()))
650 return; 661 return;
651 if (embedder_interface_->IsNewTabPageUrl(navigation_handle->GetURL())) 662 if (embedder_interface_->IsNewTabPageUrl(navigation_handle->GetURL()))
652 return; 663 return;
653 if (navigation_handle->GetURL().spec().compare(url::kAboutBlankURL) == 0) 664 if (navigation_handle->GetURL().spec().compare(url::kAboutBlankURL) == 0)
654 return; 665 return;
655 666
656 std::unique_ptr<PageLoadTracker> last_aborted =
657 NotifyAbortedProvisionalLoadsNewNavigation(navigation_handle);
658
659 int chain_size_same_url = 0; 667 int chain_size_same_url = 0;
660 int chain_size = 0; 668 int chain_size = 0;
661 if (last_aborted) { 669 if (!aborted_provisional_loads_.empty()) {
670 PageLoadTracker* last_aborted = aborted_provisional_loads_.back().get();
662 if (last_aborted->MatchesOriginalNavigation(navigation_handle)) { 671 if (last_aborted->MatchesOriginalNavigation(navigation_handle)) {
663 chain_size_same_url = last_aborted->aborted_chain_size_same_url() + 1; 672 chain_size_same_url = last_aborted->aborted_chain_size_same_url() + 1;
664 } else if (last_aborted->aborted_chain_size_same_url() > 0) { 673 } else if (last_aborted->aborted_chain_size_same_url() > 0) {
665 LogAbortChainSameURLHistogram( 674 LogAbortChainSameURLHistogram(
666 last_aborted->aborted_chain_size_same_url()); 675 last_aborted->aborted_chain_size_same_url());
667 } 676 }
668 chain_size = last_aborted->aborted_chain_size() + 1; 677 chain_size = last_aborted->aborted_chain_size() + 1;
669 } 678 }
670 679
671 // Pass in the last committed url to the PageLoadTracker. If the MWCO has 680 // Pass in the last committed url to the PageLoadTracker. If the MWCO has
(...skipping 11 matching lines...) Expand all
683 has_navigated_ = true; 692 has_navigated_ = true;
684 693
685 // We can have two provisional loads in some cases. E.g. a same-site 694 // We can have two provisional loads in some cases. E.g. a same-site
686 // navigation can have a concurrent cross-process navigation started 695 // navigation can have a concurrent cross-process navigation started
687 // from the omnibox. 696 // from the omnibox.
688 DCHECK_GT(2ul, provisional_loads_.size()); 697 DCHECK_GT(2ul, provisional_loads_.size());
689 // Passing raw pointers to observers_ and embedder_interface_ is safe because 698 // Passing raw pointers to observers_ and embedder_interface_ is safe because
690 // the MetricsWebContentsObserver owns them both list and they are torn down 699 // the MetricsWebContentsObserver owns them both list and they are torn down
691 // after the PageLoadTracker. The PageLoadTracker does not hold on to 700 // after the PageLoadTracker. The PageLoadTracker does not hold on to
692 // committed_load_ or navigation_handle beyond the scope of the constructor. 701 // committed_load_ or navigation_handle beyond the scope of the constructor.
693 provisional_loads_.insert(std::make_pair( 702 auto it = provisional_loads_.insert(std::make_pair(
694 navigation_handle, 703 navigation_handle,
695 base::WrapUnique(new PageLoadTracker( 704 base::WrapUnique(new PageLoadTracker(
696 in_foreground_, embedder_interface_.get(), currently_committed_url, 705 in_foreground_, embedder_interface_.get(), currently_committed_url,
697 navigation_handle, chain_size, chain_size_same_url)))); 706 navigation_handle, chain_size, chain_size_same_url))));
707 // Don't clear the aborted provisional loads here because
708 // WillStartNavigationRequest will soon be called, providing a better value
709 // for the page transition and user gesture.
710 NotifyAbortedProvisionalLoadsNewNavigation(it.first->second.get());
Bryan McQuade 2016/07/13 18:23:36 should we not call this and just wait to invoke it
Charlie Harrison 2016/07/13 18:58:19 It is only really for current unit tests which do
711 }
712
713 void MetricsWebContentsObserver::WillStartNavigationRequest(
714 content::NavigationHandle* navigation_handle) {
715 auto it = provisional_loads_.find(navigation_handle);
716 if (it == provisional_loads_.end())
717 return;
718 it->second->WillStartNavigationRequest(navigation_handle);
719 NotifyAbortedProvisionalLoadsNewNavigation(it->second.get());
720 aborted_provisional_loads_.clear();
698 } 721 }
699 722
700 const PageLoadExtraInfo 723 const PageLoadExtraInfo
701 MetricsWebContentsObserver::GetPageLoadExtraInfoForCommittedLoad() { 724 MetricsWebContentsObserver::GetPageLoadExtraInfoForCommittedLoad() {
702 DCHECK(committed_load_); 725 DCHECK(committed_load_);
703 return committed_load_->ComputePageLoadExtraInfo(); 726 return committed_load_->ComputePageLoadExtraInfo();
704 } 727 }
705 728
706 void MetricsWebContentsObserver::DidFinishNavigation( 729 void MetricsWebContentsObserver::DidFinishNavigation(
707 content::NavigationHandle* navigation_handle) { 730 content::NavigationHandle* navigation_handle) {
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
848 } 871 }
849 872
850 void MetricsWebContentsObserver::NotifyAbortAllLoads(UserAbortType abort_type) { 873 void MetricsWebContentsObserver::NotifyAbortAllLoads(UserAbortType abort_type) {
851 NotifyAbortAllLoadsWithTimestamp(abort_type, base::TimeTicks::Now(), true); 874 NotifyAbortAllLoadsWithTimestamp(abort_type, base::TimeTicks::Now(), true);
852 } 875 }
853 876
854 void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp( 877 void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp(
855 UserAbortType abort_type, 878 UserAbortType abort_type,
856 base::TimeTicks timestamp, 879 base::TimeTicks timestamp,
857 bool is_certainly_browser_timestamp) { 880 bool is_certainly_browser_timestamp) {
858 if (committed_load_) 881 if (committed_load_) {
859 committed_load_->NotifyAbort(abort_type, timestamp, 882 committed_load_->NotifyAbort(abort_type, timestamp,
883
860 is_certainly_browser_timestamp); 884 is_certainly_browser_timestamp);
885 }
861 for (const auto& kv : provisional_loads_) { 886 for (const auto& kv : provisional_loads_) {
862 kv.second->NotifyAbort(abort_type, timestamp, 887 kv.second->NotifyAbort(abort_type, timestamp,
863 is_certainly_browser_timestamp); 888 is_certainly_browser_timestamp);
864 } 889 }
865 for (const auto& tracker : aborted_provisional_loads_) { 890 for (const auto& tracker : aborted_provisional_loads_) {
866 if (tracker->IsLikelyProvisionalAbort(timestamp)) 891 // Only update an aborted provisional load if it has an OTHER type. Do not
892 // include UNKNOWN_NAVIGATION here because those are handled in
893 // NotifyAbortedProvisionalLoadsNewNavigation.
894 // TODO(csharrison): This is an implementation flaw due to how the unit
Bryan McQuade 2016/07/13 18:23:36 which tests in particular break due to this? is it
Charlie Harrison 2016/07/13 18:58:19 The tests that fail if we include UNKNOWN_NAVIGATI
895 // testing framework avoids calling WillStartNavigationRequest.
896 if (tracker->WasAbortedRecently(timestamp) &&
897 tracker->abort_type() == ABORT_OTHER) {
867 tracker->UpdateAbort(abort_type, timestamp, 898 tracker->UpdateAbort(abort_type, timestamp,
868 is_certainly_browser_timestamp); 899 is_certainly_browser_timestamp);
900 }
869 } 901 }
870 aborted_provisional_loads_.clear(); 902 aborted_provisional_loads_.clear();
871 } 903 }
872 904
873 std::unique_ptr<PageLoadTracker> 905 void MetricsWebContentsObserver::NotifyAbortedProvisionalLoadsNewNavigation(
874 MetricsWebContentsObserver::NotifyAbortedProvisionalLoadsNewNavigation( 906 PageLoadTracker* new_navigation) {
Bryan McQuade 2016/07/13 18:23:36 nit: given that the type is now a PageLoadTracker
Charlie Harrison 2016/07/13 18:58:19 Done.
875 content::NavigationHandle* new_navigation) {
876 // If there are multiple aborted loads that can be attributed to this one,
877 // just count the latest one for simplicity. Other loads will fall into the
878 // OTHER bucket, though there shouldn't be very many.
879 if (aborted_provisional_loads_.size() == 0) 907 if (aborted_provisional_loads_.size() == 0)
880 return nullptr; 908 return;
881 if (aborted_provisional_loads_.size() > 1) 909 if (aborted_provisional_loads_.size() > 1)
882 RecordInternalError(ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS); 910 RecordInternalError(ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS);
883 911
884 std::unique_ptr<PageLoadTracker> last_aborted_load = 912 for (const auto& it : aborted_provisional_loads_) {
885 std::move(aborted_provisional_loads_.back()); 913 base::TimeTicks timestamp = new_navigation->navigation_start();
886 aborted_provisional_loads_.pop_back(); 914 if (it->WasAbortedRecently(timestamp) &&
887 915 (it->abort_type() == ABORT_OTHER ||
888 base::TimeTicks timestamp = new_navigation->NavigationStart(); 916 it->abort_type() == ABORT_UNKNOWN_NAVIGATION)) {
889 if (last_aborted_load->IsLikelyProvisionalAbort(timestamp)) 917 const base::Optional<ui::PageTransition>& transition =
890 last_aborted_load->UpdateAbort(ABORT_UNKNOWN_NAVIGATION, timestamp, false); 918 new_navigation->page_transition();
891 919 UserAbortType abort_type =
892 aborted_provisional_loads_.clear(); 920 transition ? AbortTypeForPageTransition(transition.value())
893 return last_aborted_load; 921 : ABORT_UNKNOWN_NAVIGATION;
922 it->UpdateAbort(abort_type, timestamp, false);
923 }
924 }
894 } 925 }
895 926
896 void MetricsWebContentsObserver::OnTimingUpdated( 927 void MetricsWebContentsObserver::OnTimingUpdated(
897 content::RenderFrameHost* render_frame_host, 928 content::RenderFrameHost* render_frame_host,
898 const PageLoadTiming& timing, 929 const PageLoadTiming& timing,
899 const PageLoadMetadata& metadata) { 930 const PageLoadMetadata& metadata) {
900 bool error = false; 931 bool error = false;
901 if (!committed_load_ || !committed_load_->renderer_tracked()) { 932 if (!committed_load_ || !committed_load_->renderer_tracked()) {
902 RecordInternalError(ERR_IPC_WITH_NO_RELEVANT_LOAD); 933 RecordInternalError(ERR_IPC_WITH_NO_RELEVANT_LOAD);
903 error = true; 934 error = true;
(...skipping 19 matching lines...) Expand all
923 954
924 if (!committed_load_->UpdateTiming(timing, metadata)) { 955 if (!committed_load_->UpdateTiming(timing, metadata)) {
925 // If the page load tracker cannot update its timing, something is wrong 956 // If the page load tracker cannot update its timing, something is wrong
926 // with the IPC (it's from another load, or it's invalid in some other way). 957 // with the IPC (it's from another load, or it's invalid in some other way).
927 // We expect this to be a rare occurrence. 958 // We expect this to be a rare occurrence.
928 RecordInternalError(ERR_BAD_TIMING_IPC); 959 RecordInternalError(ERR_BAD_TIMING_IPC);
929 } 960 }
930 } 961 }
931 962
932 } // namespace page_load_metrics 963 } // namespace page_load_metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698