| 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 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 | 181 |
| 182 void RecordInternalError(InternalErrorLoadEvent event) { | 182 void RecordInternalError(InternalErrorLoadEvent event) { |
| 183 UMA_HISTOGRAM_ENUMERATION(internal::kErrorEvents, event, ERR_LAST_ENTRY); | 183 UMA_HISTOGRAM_ENUMERATION(internal::kErrorEvents, event, ERR_LAST_ENTRY); |
| 184 } | 184 } |
| 185 | 185 |
| 186 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { | 186 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { |
| 187 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, | 187 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, |
| 188 completed_after_background); | 188 completed_after_background); |
| 189 } | 189 } |
| 190 | 190 |
| 191 // TODO(csharrison): Add a case for client side redirects, which is what JS |
| 192 // initiated window.location / window.history navigations get set to. |
| 191 UserAbortType AbortTypeForPageTransition(ui::PageTransition transition) { | 193 UserAbortType AbortTypeForPageTransition(ui::PageTransition transition) { |
| 192 if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD)) | 194 if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD)) |
| 193 return ABORT_RELOAD; | 195 return ABORT_RELOAD; |
| 194 if (transition & ui::PAGE_TRANSITION_FORWARD_BACK) | 196 if (transition & ui::PAGE_TRANSITION_FORWARD_BACK) |
| 195 return ABORT_FORWARD_BACK; | 197 return ABORT_FORWARD_BACK; |
| 196 if (ui::PageTransitionIsNewNavigation(transition)) | 198 if (ui::PageTransitionIsNewNavigation(transition)) |
| 197 return ABORT_NEW_NAVIGATION; | 199 return ABORT_NEW_NAVIGATION; |
| 198 NOTREACHED() | 200 NOTREACHED() |
| 199 << "AbortTypeForPageTransition received unexpected ui::PageTransition: " | 201 << "AbortTypeForPageTransition received unexpected ui::PageTransition: " |
| 200 << transition; | 202 << transition; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 const GURL& currently_committed_url, | 248 const GURL& currently_committed_url, |
| 247 content::NavigationHandle* navigation_handle, | 249 content::NavigationHandle* navigation_handle, |
| 248 int aborted_chain_size, | 250 int aborted_chain_size, |
| 249 int aborted_chain_size_same_url) | 251 int aborted_chain_size_same_url) |
| 250 : did_stop_tracking_(false), | 252 : did_stop_tracking_(false), |
| 251 app_entered_background_(false), | 253 app_entered_background_(false), |
| 252 navigation_start_(navigation_handle->NavigationStart()), | 254 navigation_start_(navigation_handle->NavigationStart()), |
| 253 url_(navigation_handle->GetURL()), | 255 url_(navigation_handle->GetURL()), |
| 254 abort_type_(ABORT_NONE), | 256 abort_type_(ABORT_NONE), |
| 255 started_in_foreground_(in_foreground), | 257 started_in_foreground_(in_foreground), |
| 258 page_transition_(navigation_handle->GetPageTransition()), |
| 256 aborted_chain_size_(aborted_chain_size), | 259 aborted_chain_size_(aborted_chain_size), |
| 257 aborted_chain_size_same_url_(aborted_chain_size_same_url), | 260 aborted_chain_size_same_url_(aborted_chain_size_same_url), |
| 258 embedder_interface_(embedder_interface) { | 261 embedder_interface_(embedder_interface) { |
| 259 DCHECK(!navigation_handle->HasCommitted()); | 262 DCHECK(!navigation_handle->HasCommitted()); |
| 260 embedder_interface_->RegisterObservers(this); | 263 embedder_interface_->RegisterObservers(this); |
| 261 for (const auto& observer : observers_) { | 264 for (const auto& observer : observers_) { |
| 262 observer->OnStart(navigation_handle, currently_committed_url, | 265 observer->OnStart(navigation_handle, currently_committed_url, |
| 263 started_in_foreground_); | 266 started_in_foreground_); |
| 264 } | 267 } |
| 265 } | 268 } |
| 266 | 269 |
| 267 PageLoadTracker::~PageLoadTracker() { | 270 PageLoadTracker::~PageLoadTracker() { |
| 268 if (app_entered_background_) { | 271 if (app_entered_background_) { |
| 269 RecordAppBackgroundPageLoadCompleted(true); | 272 RecordAppBackgroundPageLoadCompleted(true); |
| 270 } | 273 } |
| 271 | 274 |
| 272 if (did_stop_tracking_) | 275 if (did_stop_tracking_) |
| 273 return; | 276 return; |
| 274 | 277 |
| 275 if (commit_time_.is_null()) { | 278 if (commit_time_.is_null()) { |
| 276 if (!failed_provisional_load_info_) | 279 if (!failed_provisional_load_info_) |
| 277 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); | 280 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); |
| 278 | 281 |
| 279 // Recall that trackers that are given ABORT_UNKNOWN_NAVIGATION have their | 282 // Don't include any aborts that resulted in a new navigation, as the chain |
| 280 // chain length added to the next navigation. Take care not to double count | 283 // length will be included in the aborter PageLoadTracker. |
| 281 // them. Also do not double count committed loads, which call this already. | 284 if (abort_type_ != ABORT_RELOAD && abort_type_ != ABORT_FORWARD_BACK && |
| 282 if (abort_type_ != ABORT_UNKNOWN_NAVIGATION) | 285 abort_type_ != ABORT_NEW_NAVIGATION) { |
| 283 LogAbortChainHistograms(nullptr); | 286 LogAbortChainHistograms(nullptr); |
| 287 } |
| 284 } else if (timing_.IsEmpty()) { | 288 } else if (timing_.IsEmpty()) { |
| 285 RecordInternalError(ERR_NO_IPCS_RECEIVED); | 289 RecordInternalError(ERR_NO_IPCS_RECEIVED); |
| 286 PAGE_LOAD_HISTOGRAM(internal::kCommitToCompleteNoTimingIPCs, | 290 PAGE_LOAD_HISTOGRAM(internal::kCommitToCompleteNoTimingIPCs, |
| 287 base::TimeTicks::Now() - commit_time_); | 291 base::TimeTicks::Now() - commit_time_); |
| 288 } | 292 } |
| 289 | 293 |
| 290 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 294 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 291 for (const auto& observer : observers_) { | 295 for (const auto& observer : observers_) { |
| 292 if (failed_provisional_load_info_) { | 296 if (failed_provisional_load_info_) { |
| 293 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); | 297 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 for (const auto& observer : observers_) | 375 for (const auto& observer : observers_) |
| 372 observer->OnShown(); | 376 observer->OnShown(); |
| 373 } | 377 } |
| 374 | 378 |
| 375 void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) { | 379 void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) { |
| 376 // TODO(bmcquade): To improve accuracy, consider adding commit time to | 380 // TODO(bmcquade): To improve accuracy, consider adding commit time to |
| 377 // NavigationHandle. Taking a timestamp here should be close enough for now. | 381 // NavigationHandle. Taking a timestamp here should be close enough for now. |
| 378 commit_time_ = base::TimeTicks::Now(); | 382 commit_time_ = base::TimeTicks::Now(); |
| 379 ClampBrowserTimestampIfInterProcessTimeTickSkew(&commit_time_); | 383 ClampBrowserTimestampIfInterProcessTimeTickSkew(&commit_time_); |
| 380 url_ = navigation_handle->GetURL(); | 384 url_ = navigation_handle->GetURL(); |
| 385 // Some transitions (like CLIENT_REDIRECT) are only known at commit time. |
| 386 page_transition_ = navigation_handle->GetPageTransition(); |
| 381 for (const auto& observer : observers_) { | 387 for (const auto& observer : observers_) { |
| 382 observer->OnCommit(navigation_handle); | 388 observer->OnCommit(navigation_handle); |
| 383 } | 389 } |
| 384 LogAbortChainHistograms(navigation_handle); | 390 LogAbortChainHistograms(navigation_handle); |
| 385 } | 391 } |
| 386 | 392 |
| 387 void PageLoadTracker::FailedProvisionalLoad( | 393 void PageLoadTracker::FailedProvisionalLoad( |
| 388 content::NavigationHandle* navigation_handle) { | 394 content::NavigationHandle* navigation_handle) { |
| 389 DCHECK(!failed_provisional_load_info_); | 395 DCHECK(!failed_provisional_load_info_); |
| 390 failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo( | 396 failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo( |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 DCHECK_EQ(abort_type_, ABORT_OTHER); | 558 DCHECK_EQ(abort_type_, ABORT_OTHER); |
| 553 | 559 |
| 554 // For some aborts (e.g. navigations), the initiated timestamp can be earlier | 560 // For some aborts (e.g. navigations), the initiated timestamp can be earlier |
| 555 // than the timestamp that aborted the load. Taking the minimum gives the | 561 // than the timestamp that aborted the load. Taking the minimum gives the |
| 556 // closest user initiated time known. | 562 // closest user initiated time known. |
| 557 UpdateAbortInternal(abort_type, std::min(abort_time_, timestamp), | 563 UpdateAbortInternal(abort_type, std::min(abort_time_, timestamp), |
| 558 is_certainly_browser_timestamp); | 564 is_certainly_browser_timestamp); |
| 559 } | 565 } |
| 560 | 566 |
| 561 bool PageLoadTracker::IsLikelyProvisionalAbort( | 567 bool PageLoadTracker::IsLikelyProvisionalAbort( |
| 562 base::TimeTicks abort_cause_time) { | 568 base::TimeTicks abort_cause_time) const { |
| 563 // Note that |abort_cause_time - abort_time| can be negative. | 569 // Note that |abort_cause_time - abort_time| can be negative. |
| 564 return abort_type_ == ABORT_OTHER && | 570 return abort_type_ == ABORT_OTHER && |
| 565 (abort_cause_time - abort_time_).InMilliseconds() < 100; | 571 (abort_cause_time - abort_time_).InMilliseconds() < 100; |
| 566 } | 572 } |
| 567 | 573 |
| 568 bool PageLoadTracker::MatchesOriginalNavigation( | 574 bool PageLoadTracker::MatchesOriginalNavigation( |
| 569 content::NavigationHandle* navigation_handle) { | 575 content::NavigationHandle* navigation_handle) { |
| 570 // Neither navigation should have committed. | 576 // Neither navigation should have committed. |
| 571 DCHECK(!navigation_handle->HasCommitted()); | 577 DCHECK(!navigation_handle->HasCommitted()); |
| 572 DCHECK(commit_time_.is_null()); | 578 DCHECK(commit_time_.is_null()); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 659 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 654 bool handled = true; | 660 bool handled = true; |
| 655 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message, | 661 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message, |
| 656 render_frame_host) | 662 render_frame_host) |
| 657 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) | 663 IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated) |
| 658 IPC_MESSAGE_UNHANDLED(handled = false) | 664 IPC_MESSAGE_UNHANDLED(handled = false) |
| 659 IPC_END_MESSAGE_MAP() | 665 IPC_END_MESSAGE_MAP() |
| 660 return handled; | 666 return handled; |
| 661 } | 667 } |
| 662 | 668 |
| 663 void MetricsWebContentsObserver::DidStartNavigation( | 669 void MetricsWebContentsObserver::WillStartNavigationRequest( |
| 664 content::NavigationHandle* navigation_handle) { | 670 content::NavigationHandle* navigation_handle) { |
| 665 if (!navigation_handle->IsInMainFrame()) | 671 if (!navigation_handle->IsInMainFrame()) |
| 666 return; | 672 return; |
| 667 | 673 |
| 668 std::unique_ptr<PageLoadTracker> last_aborted = | 674 std::unique_ptr<PageLoadTracker> last_aborted = |
| 669 NotifyAbortedProvisionalLoadsNewNavigation(navigation_handle); | 675 NotifyAbortedProvisionalLoadsNewNavigation(navigation_handle); |
| 670 | 676 |
| 671 int chain_size_same_url = 0; | 677 int chain_size_same_url = 0; |
| 672 int chain_size = 0; | 678 int chain_size = 0; |
| 673 if (last_aborted) { | 679 if (last_aborted) { |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 883 } | 889 } |
| 884 | 890 |
| 885 void MetricsWebContentsObserver::NotifyAbortAllLoads(UserAbortType abort_type) { | 891 void MetricsWebContentsObserver::NotifyAbortAllLoads(UserAbortType abort_type) { |
| 886 NotifyAbortAllLoadsWithTimestamp(abort_type, base::TimeTicks::Now(), true); | 892 NotifyAbortAllLoadsWithTimestamp(abort_type, base::TimeTicks::Now(), true); |
| 887 } | 893 } |
| 888 | 894 |
| 889 void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp( | 895 void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp( |
| 890 UserAbortType abort_type, | 896 UserAbortType abort_type, |
| 891 base::TimeTicks timestamp, | 897 base::TimeTicks timestamp, |
| 892 bool is_certainly_browser_timestamp) { | 898 bool is_certainly_browser_timestamp) { |
| 893 if (committed_load_) | 899 if (committed_load_) { |
| 894 committed_load_->NotifyAbort(abort_type, timestamp, | 900 committed_load_->NotifyAbort(abort_type, timestamp, |
| 895 is_certainly_browser_timestamp); | 901 is_certainly_browser_timestamp); |
| 902 } |
| 896 for (const auto& kv : provisional_loads_) { | 903 for (const auto& kv : provisional_loads_) { |
| 897 kv.second->NotifyAbort(abort_type, timestamp, | 904 kv.second->NotifyAbort(abort_type, timestamp, |
| 898 is_certainly_browser_timestamp); | 905 is_certainly_browser_timestamp); |
| 899 } | 906 } |
| 900 for (const auto& tracker : aborted_provisional_loads_) { | 907 for (const auto& tracker : aborted_provisional_loads_) { |
| 901 if (tracker->IsLikelyProvisionalAbort(timestamp)) | 908 if (tracker->IsLikelyProvisionalAbort(timestamp)) { |
| 902 tracker->UpdateAbort(abort_type, timestamp, | 909 tracker->UpdateAbort(abort_type, timestamp, |
| 903 is_certainly_browser_timestamp); | 910 is_certainly_browser_timestamp); |
| 911 } |
| 904 } | 912 } |
| 905 aborted_provisional_loads_.clear(); | 913 aborted_provisional_loads_.clear(); |
| 906 } | 914 } |
| 907 | 915 |
| 908 std::unique_ptr<PageLoadTracker> | 916 std::unique_ptr<PageLoadTracker> |
| 909 MetricsWebContentsObserver::NotifyAbortedProvisionalLoadsNewNavigation( | 917 MetricsWebContentsObserver::NotifyAbortedProvisionalLoadsNewNavigation( |
| 910 content::NavigationHandle* new_navigation) { | 918 content::NavigationHandle* new_navigation) { |
| 911 // If there are multiple aborted loads that can be attributed to this one, | 919 // If there are multiple aborted loads that can be attributed to this one, |
| 912 // just count the latest one for simplicity. Other loads will fall into the | 920 // just count the latest one for simplicity. Other loads will fall into the |
| 913 // OTHER bucket, though there shouldn't be very many. | 921 // OTHER bucket, though there shouldn't be very many. |
| 914 if (aborted_provisional_loads_.size() == 0) | 922 if (aborted_provisional_loads_.size() == 0) |
| 915 return nullptr; | 923 return nullptr; |
| 916 if (aborted_provisional_loads_.size() > 1) | 924 if (aborted_provisional_loads_.size() > 1) |
| 917 RecordInternalError(ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS); | 925 RecordInternalError(ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS); |
| 918 | 926 |
| 919 std::unique_ptr<PageLoadTracker> last_aborted_load = | 927 std::unique_ptr<PageLoadTracker> last_aborted_load = |
| 920 std::move(aborted_provisional_loads_.back()); | 928 std::move(aborted_provisional_loads_.back()); |
| 921 aborted_provisional_loads_.pop_back(); | 929 aborted_provisional_loads_.pop_back(); |
| 922 | 930 |
| 923 base::TimeTicks timestamp = new_navigation->NavigationStart(); | 931 base::TimeTicks timestamp = new_navigation->NavigationStart(); |
| 924 if (last_aborted_load->IsLikelyProvisionalAbort(timestamp)) | 932 if (last_aborted_load->IsLikelyProvisionalAbort(timestamp)) { |
| 925 last_aborted_load->UpdateAbort(ABORT_UNKNOWN_NAVIGATION, timestamp, false); | 933 last_aborted_load->UpdateAbort( |
| 934 AbortTypeForPageTransition(new_navigation->GetPageTransition()), |
| 935 timestamp, false); |
| 936 } |
| 926 | 937 |
| 927 aborted_provisional_loads_.clear(); | 938 aborted_provisional_loads_.clear(); |
| 928 return last_aborted_load; | 939 return last_aborted_load; |
| 929 } | 940 } |
| 930 | 941 |
| 931 void MetricsWebContentsObserver::OnTimingUpdated( | 942 void MetricsWebContentsObserver::OnTimingUpdated( |
| 932 content::RenderFrameHost* render_frame_host, | 943 content::RenderFrameHost* render_frame_host, |
| 933 const PageLoadTiming& timing, | 944 const PageLoadTiming& timing, |
| 934 const PageLoadMetadata& metadata) { | 945 const PageLoadMetadata& metadata) { |
| 935 // We may receive notifications from frames that have been navigated away | 946 // We may receive notifications from frames that have been navigated away |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 976 if (navigation_handle->IsSamePage() || navigation_handle->IsErrorPage()) | 987 if (navigation_handle->IsSamePage() || navigation_handle->IsErrorPage()) |
| 977 return false; | 988 return false; |
| 978 const std::string& mime_type = web_contents()->GetContentsMimeType(); | 989 const std::string& mime_type = web_contents()->GetContentsMimeType(); |
| 979 if (mime_type != "text/html" && mime_type != "application/xhtml+xml") | 990 if (mime_type != "text/html" && mime_type != "application/xhtml+xml") |
| 980 return false; | 991 return false; |
| 981 } | 992 } |
| 982 return true; | 993 return true; |
| 983 } | 994 } |
| 984 | 995 |
| 985 } // namespace page_load_metrics | 996 } // namespace page_load_metrics |
| OLD | NEW |