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

Side by Side Diff: chrome/browser/page_load_metrics/page_load_tracker.cc

Issue 2545593003: Additional heuristic user interaction attribution for page load metrics (Closed)
Patch Set: address comments Created 4 years 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/page_load_tracker.h" 5 #include "chrome/browser/page_load_metrics/page_load_tracker.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 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 observer->OnLoadingBehaviorObserved(extra_info); 280 observer->OnLoadingBehaviorObserved(extra_info);
281 } 281 }
282 282
283 } // namespace 283 } // namespace
284 284
285 PageLoadTracker::PageLoadTracker( 285 PageLoadTracker::PageLoadTracker(
286 bool in_foreground, 286 bool in_foreground,
287 PageLoadMetricsEmbedderInterface* embedder_interface, 287 PageLoadMetricsEmbedderInterface* embedder_interface,
288 const GURL& currently_committed_url, 288 const GURL& currently_committed_url,
289 content::NavigationHandle* navigation_handle, 289 content::NavigationHandle* navigation_handle,
290 UserInitiatedInfo user_initiated_info,
290 int aborted_chain_size, 291 int aborted_chain_size,
291 int aborted_chain_size_same_url) 292 int aborted_chain_size_same_url)
292 : did_stop_tracking_(false), 293 : did_stop_tracking_(false),
293 app_entered_background_(false), 294 app_entered_background_(false),
294 navigation_start_(navigation_handle->NavigationStart()), 295 navigation_start_(navigation_handle->NavigationStart()),
295 start_url_(navigation_handle->GetURL()), 296 start_url_(navigation_handle->GetURL()),
296 abort_type_(ABORT_NONE), 297 abort_type_(ABORT_NONE),
297 abort_user_initiated_(false), 298 abort_user_initiated_info_(UserInitiatedInfo::NotUserInitiated()),
298 started_in_foreground_(in_foreground), 299 started_in_foreground_(in_foreground),
299 page_transition_(navigation_handle->GetPageTransition()), 300 page_transition_(navigation_handle->GetPageTransition()),
300 num_cache_requests_(0), 301 num_cache_requests_(0),
301 num_network_requests_(0), 302 num_network_requests_(0),
302 user_initiated_(IsNavigationUserInitiated(navigation_handle)), 303 user_initiated_info_(user_initiated_info),
303 aborted_chain_size_(aborted_chain_size), 304 aborted_chain_size_(aborted_chain_size),
304 aborted_chain_size_same_url_(aborted_chain_size_same_url), 305 aborted_chain_size_same_url_(aborted_chain_size_same_url),
305 embedder_interface_(embedder_interface) { 306 embedder_interface_(embedder_interface) {
306 DCHECK(!navigation_handle->HasCommitted()); 307 DCHECK(!navigation_handle->HasCommitted());
307 if (embedder_interface_->IsPrerendering( 308 if (embedder_interface_->IsPrerendering(
308 navigation_handle->GetWebContents())) { 309 navigation_handle->GetWebContents())) {
309 DCHECK(!started_in_foreground_); 310 DCHECK(!started_in_foreground_);
310 // For the time being, we do not track prerenders. See crbug.com/648338 for 311 // For the time being, we do not track prerenders. See crbug.com/648338 for
311 // details. 312 // details.
312 StopTracking(); 313 StopTracking();
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 // Make sure we either started in the foreground and haven't been 408 // Make sure we either started in the foreground and haven't been
408 // foregrounded yet, or started in the background and have already been 409 // foregrounded yet, or started in the background and have already been
409 // foregrounded. 410 // foregrounded.
410 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); 411 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null());
411 background_time_ = base::TimeTicks::Now(); 412 background_time_ = base::TimeTicks::Now();
412 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); 413 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_);
413 // Though most cases where a tab is backgrounded are user initiated, we 414 // Though most cases where a tab is backgrounded are user initiated, we
414 // can't be certain that we were backgrounded due to a user action. For 415 // can't be certain that we were backgrounded due to a user action. For
415 // example, on Android, the screen times out after a period of inactivity, 416 // example, on Android, the screen times out after a period of inactivity,
416 // resulting in a non-user-initiated backgrounding. 417 // resulting in a non-user-initiated backgrounding.
417 const bool abort_is_user_initiated = false; 418 NotifyAbort(ABORT_BACKGROUND, UserInitiatedInfo::NotUserInitiated(),
418 NotifyAbort(ABORT_BACKGROUND, abort_is_user_initiated, background_time_, 419 background_time_, true);
419 true);
420 } 420 }
421 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); 421 const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
422 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, timing_, info); 422 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, timing_, info);
423 } 423 }
424 424
425 void PageLoadTracker::WebContentsShown() { 425 void PageLoadTracker::WebContentsShown() {
426 // Only log the first time we foreground in a given page load. 426 // Only log the first time we foreground in a given page load.
427 if (foreground_time_.is_null()) { 427 if (foreground_time_.is_null()) {
428 // Make sure we either started in the background and haven't been 428 // Make sure we either started in the background and haven't been
429 // backgrounded yet, or started in the foreground and have already been 429 // backgrounded yet, or started in the foreground and have already been
430 // backgrounded. 430 // backgrounded.
431 DCHECK_NE(started_in_foreground_, background_time_.is_null()); 431 DCHECK_NE(started_in_foreground_, background_time_.is_null());
432 foreground_time_ = base::TimeTicks::Now(); 432 foreground_time_ = base::TimeTicks::Now();
433 ClampBrowserTimestampIfInterProcessTimeTickSkew(&foreground_time_); 433 ClampBrowserTimestampIfInterProcessTimeTickSkew(&foreground_time_);
434 } 434 }
435 435
436 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnShown); 436 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnShown);
437 } 437 }
438 438
439 void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) { 439 void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) {
440 committed_url_ = navigation_handle->GetURL(); 440 committed_url_ = navigation_handle->GetURL();
441 // Some transitions (like CLIENT_REDIRECT) are only known at commit time. 441 // Some transitions (like CLIENT_REDIRECT) are only known at commit time.
442 page_transition_ = navigation_handle->GetPageTransition(); 442 page_transition_ = navigation_handle->GetPageTransition();
443 user_initiated_ = IsNavigationUserInitiated(navigation_handle); 443 user_initiated_info_.user_gesture = navigation_handle->HasUserGesture();
444 444
445 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnCommit, navigation_handle); 445 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnCommit, navigation_handle);
446 LogAbortChainHistograms(navigation_handle); 446 LogAbortChainHistograms(navigation_handle);
447 } 447 }
448 448
449 void PageLoadTracker::FailedProvisionalLoad( 449 void PageLoadTracker::FailedProvisionalLoad(
450 content::NavigationHandle* navigation_handle) { 450 content::NavigationHandle* navigation_handle) {
451 DCHECK(!failed_provisional_load_info_); 451 DCHECK(!failed_provisional_load_info_);
452 failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo( 452 failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo(
453 base::TimeTicks::Now() - navigation_handle->NavigationStart(), 453 base::TimeTicks::Now() - navigation_handle->NavigationStart(),
454 navigation_handle->GetNetErrorCode())); 454 navigation_handle->GetNetErrorCode()));
455 } 455 }
456 456
457 void PageLoadTracker::Redirect(content::NavigationHandle* navigation_handle) { 457 void PageLoadTracker::Redirect(content::NavigationHandle* navigation_handle) {
458 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnRedirect, navigation_handle); 458 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnRedirect, navigation_handle);
459 } 459 }
460 460
461 void PageLoadTracker::OnInputEvent(const blink::WebInputEvent& event) { 461 void PageLoadTracker::OnInputEvent(const blink::WebInputEvent& event) {
462 input_tracker_.OnInputEvent(event);
462 for (const auto& observer : observers_) { 463 for (const auto& observer : observers_) {
463 observer->OnUserInput(event); 464 observer->OnUserInput(event);
464 } 465 }
465 } 466 }
466 467
467 void PageLoadTracker::FlushMetricsOnAppEnterBackground() { 468 void PageLoadTracker::FlushMetricsOnAppEnterBackground() {
468 if (!app_entered_background_) { 469 if (!app_entered_background_) {
469 RecordAppBackgroundPageLoadCompleted(false); 470 RecordAppBackgroundPageLoadCompleted(false);
470 app_entered_background_ = true; 471 app_entered_background_ = true;
471 } 472 }
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 first_foreground_time = foreground_time_ - navigation_start_; 589 first_foreground_time = foreground_time_ - navigation_start_;
589 } 590 }
590 591
591 if (abort_type_ != ABORT_NONE) { 592 if (abort_type_ != ABORT_NONE) {
592 DCHECK_GE(abort_time_, navigation_start_); 593 DCHECK_GE(abort_time_, navigation_start_);
593 time_to_abort = abort_time_ - navigation_start_; 594 time_to_abort = abort_time_ - navigation_start_;
594 } else { 595 } else {
595 DCHECK(abort_time_.is_null()); 596 DCHECK(abort_time_.is_null());
596 } 597 }
597 598
598 // abort_type_ == ABORT_NONE implies !abort_user_initiated_. 599 // abort_type_ == ABORT_NONE implies abort_user_initiated_info_ is not user
599 DCHECK(abort_type_ != ABORT_NONE || !abort_user_initiated_); 600 // initiated.
601 DCHECK(abort_type_ != ABORT_NONE ||
602 (!abort_user_initiated_info_.browser_initiated &&
603 !abort_user_initiated_info_.user_gesture &&
604 !abort_user_initiated_info_.user_input_event));
600 return PageLoadExtraInfo( 605 return PageLoadExtraInfo(
601 first_background_time, first_foreground_time, started_in_foreground_, 606 first_background_time, first_foreground_time, started_in_foreground_,
602 user_initiated_, committed_url_, start_url_, abort_type_, 607 user_initiated_info_, committed_url_, start_url_, abort_type_,
603 abort_user_initiated_, time_to_abort, num_cache_requests_, 608 abort_user_initiated_info_, time_to_abort, num_cache_requests_,
604 num_network_requests_, metadata_); 609 num_network_requests_, metadata_);
605 } 610 }
606 611
607 void PageLoadTracker::NotifyAbort(UserAbortType abort_type, 612 void PageLoadTracker::NotifyAbort(UserAbortType abort_type,
608 bool user_initiated, 613 UserInitiatedInfo user_initiated_info,
609 base::TimeTicks timestamp, 614 base::TimeTicks timestamp,
610 bool is_certainly_browser_timestamp) { 615 bool is_certainly_browser_timestamp) {
611 DCHECK_NE(abort_type, ABORT_NONE); 616 DCHECK_NE(abort_type, ABORT_NONE);
612 // Use UpdateAbort to update an already notified PageLoadTracker. 617 // Use UpdateAbort to update an already notified PageLoadTracker.
613 if (abort_type_ != ABORT_NONE) 618 if (abort_type_ != ABORT_NONE)
614 return; 619 return;
615 620
616 UpdateAbortInternal(abort_type, user_initiated, timestamp, 621 UpdateAbortInternal(abort_type, user_initiated_info, timestamp,
617 is_certainly_browser_timestamp); 622 is_certainly_browser_timestamp);
618 } 623 }
619 624
620 void PageLoadTracker::UpdateAbort(UserAbortType abort_type, 625 void PageLoadTracker::UpdateAbort(UserAbortType abort_type,
621 bool user_initiated, 626 UserInitiatedInfo user_initiated_info,
622 base::TimeTicks timestamp, 627 base::TimeTicks timestamp,
623 bool is_certainly_browser_timestamp) { 628 bool is_certainly_browser_timestamp) {
624 DCHECK_NE(abort_type, ABORT_NONE); 629 DCHECK_NE(abort_type, ABORT_NONE);
625 DCHECK_NE(abort_type, ABORT_OTHER); 630 DCHECK_NE(abort_type, ABORT_OTHER);
626 DCHECK_EQ(abort_type_, ABORT_OTHER); 631 DCHECK_EQ(abort_type_, ABORT_OTHER);
627 632
628 // For some aborts (e.g. navigations), the initiated timestamp can be earlier 633 // For some aborts (e.g. navigations), the initiated timestamp can be earlier
629 // than the timestamp that aborted the load. Taking the minimum gives the 634 // than the timestamp that aborted the load. Taking the minimum gives the
630 // closest user initiated time known. 635 // closest user initiated time known.
631 UpdateAbortInternal(abort_type, user_initiated, 636 UpdateAbortInternal(abort_type, user_initiated_info,
632 std::min(abort_time_, timestamp), 637 std::min(abort_time_, timestamp),
633 is_certainly_browser_timestamp); 638 is_certainly_browser_timestamp);
634 } 639 }
635 640
636 bool PageLoadTracker::IsLikelyProvisionalAbort( 641 bool PageLoadTracker::IsLikelyProvisionalAbort(
637 base::TimeTicks abort_cause_time) const { 642 base::TimeTicks abort_cause_time) const {
638 // Note that |abort_cause_time - abort_time| can be negative. 643 // Note that |abort_cause_time - abort_time| can be negative.
639 return abort_type_ == ABORT_OTHER && 644 return abort_type_ == ABORT_OTHER &&
640 (abort_cause_time - abort_time_).InMilliseconds() < 100; 645 (abort_cause_time - abort_time_).InMilliseconds() < 100;
641 } 646 }
642 647
643 bool PageLoadTracker::MatchesOriginalNavigation( 648 bool PageLoadTracker::MatchesOriginalNavigation(
644 content::NavigationHandle* navigation_handle) { 649 content::NavigationHandle* navigation_handle) {
645 // Neither navigation should have committed. 650 // Neither navigation should have committed.
646 DCHECK(!navigation_handle->HasCommitted()); 651 DCHECK(!navigation_handle->HasCommitted());
647 DCHECK(committed_url_.is_empty()); 652 DCHECK(committed_url_.is_empty());
648 return navigation_handle->GetURL() == start_url_; 653 return navigation_handle->GetURL() == start_url_;
649 } 654 }
650 655
651 void PageLoadTracker::UpdateAbortInternal(UserAbortType abort_type, 656 void PageLoadTracker::UpdateAbortInternal(UserAbortType abort_type,
652 bool user_initiated, 657 UserInitiatedInfo user_initiated_info,
653 base::TimeTicks timestamp, 658 base::TimeTicks timestamp,
654 bool is_certainly_browser_timestamp) { 659 bool is_certainly_browser_timestamp) {
655 // When a provisional navigation commits, that navigation's start time is 660 // When a provisional navigation commits, that navigation's start time is
656 // interpreted as the abort time for other provisional loads in the tab. 661 // interpreted as the abort time for other provisional loads in the tab.
657 // However, this only makes sense if the committed load started after the 662 // However, this only makes sense if the committed load started after the
658 // aborted provisional loads started. Thus we ignore cases where the committed 663 // aborted provisional loads started. Thus we ignore cases where the committed
659 // load started before the aborted provisional load, as this would result in 664 // load started before the aborted provisional load, as this would result in
660 // recording a negative time-to-abort. The real issue here is that we have to 665 // recording a negative time-to-abort. The real issue here is that we have to
661 // infer the cause of aborts. It would be better if the navigation code could 666 // infer the cause of aborts. It would be better if the navigation code could
662 // instead report the actual cause of an aborted navigation. See crbug/571647 667 // instead report the actual cause of an aborted navigation. See crbug/571647
663 // for details. 668 // for details.
664 if (timestamp < navigation_start_) { 669 if (timestamp < navigation_start_) {
665 RecordInternalError(ERR_ABORT_BEFORE_NAVIGATION_START); 670 RecordInternalError(ERR_ABORT_BEFORE_NAVIGATION_START);
666 abort_type_ = ABORT_NONE; 671 abort_type_ = ABORT_NONE;
667 abort_time_ = base::TimeTicks(); 672 abort_time_ = base::TimeTicks();
668 return; 673 return;
669 } 674 }
670 abort_type_ = abort_type; 675 abort_type_ = abort_type;
671 abort_time_ = timestamp; 676 abort_time_ = timestamp;
672 // A client redirect can never be user initiated. Due to the way Blink 677 // A client redirect can never be user initiated. Due to the way Blink
673 // implements user gesture tracking, where all events that occur within 1 678 // implements user gesture tracking, where all events that occur within 1
674 // second after a user interaction are considered to be triggered by user 679 // second after a user interaction are considered to be triggered by user
675 // activation (based on HTML spec: 680 // activation (based on HTML spec:
676 // https://html.spec.whatwg.org/multipage/interaction.html#triggered-by-user-a ctivation), 681 // https://html.spec.whatwg.org/multipage/interaction.html#triggered-by-user-a ctivation),
677 // these navs may sometimes be reported as user initiated by Blink. Thus, we 682 // these navs may sometimes be reported as user initiated by Blink. Thus, we
678 // explicitly filter these types of aborts out when deciding if the abort was 683 // explicitly filter these types of aborts out when deciding if the abort was
679 // user initiated. 684 // user initiated.
680 abort_user_initiated_ = user_initiated && abort_type != ABORT_CLIENT_REDIRECT; 685 if (abort_type != ABORT_CLIENT_REDIRECT)
686 abort_user_initiated_info_ = user_initiated_info;
681 687
682 if (is_certainly_browser_timestamp) { 688 if (is_certainly_browser_timestamp) {
683 ClampBrowserTimestampIfInterProcessTimeTickSkew(&abort_time_); 689 ClampBrowserTimestampIfInterProcessTimeTickSkew(&abort_time_);
684 } 690 }
685 } 691 }
686 692
687 } // namespace page_load_metrics 693 } // namespace page_load_metrics
OLDNEW
« no previous file with comments | « chrome/browser/page_load_metrics/page_load_tracker.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698