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 |