| 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 |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 embedder_interface_(embedder_interface) { | 253 embedder_interface_(embedder_interface) { |
| 254 DCHECK(!navigation_handle->HasCommitted()); | 254 DCHECK(!navigation_handle->HasCommitted()); |
| 255 embedder_interface_->RegisterObservers(this); | 255 embedder_interface_->RegisterObservers(this); |
| 256 for (const auto& observer : observers_) { | 256 for (const auto& observer : observers_) { |
| 257 observer->OnStart(navigation_handle, currently_committed_url, | 257 observer->OnStart(navigation_handle, currently_committed_url, |
| 258 started_in_foreground_); | 258 started_in_foreground_); |
| 259 } | 259 } |
| 260 } | 260 } |
| 261 | 261 |
| 262 PageLoadTracker::~PageLoadTracker() { | 262 PageLoadTracker::~PageLoadTracker() { |
| 263 const PageLoadExtraInfo info = GetPageLoadMetricsInfo(); | 263 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 264 if (!info.time_to_commit.is_zero() && renderer_tracked() && | 264 |
| 265 timing_.IsEmpty()) { | 265 if (info.time_to_commit && renderer_tracked() && timing_.IsEmpty()) { |
| 266 RecordInternalError(ERR_NO_IPCS_RECEIVED); | 266 RecordInternalError(ERR_NO_IPCS_RECEIVED); |
| 267 } | 267 } |
| 268 // Recall that trackers that are given ABORT_UNKNOWN_NAVIGATION have their | 268 // Recall that trackers that are given ABORT_UNKNOWN_NAVIGATION have their |
| 269 // chain length added to the next navigation. Take care not to double count | 269 // chain length added to the next navigation. Take care not to double count |
| 270 // them. Also do not double count committed loads, which call this already. | 270 // them. Also do not double count committed loads, which call this already. |
| 271 if (commit_time_.is_null() && abort_type_ != ABORT_UNKNOWN_NAVIGATION) | 271 if (commit_time_.is_null() && abort_type_ != ABORT_UNKNOWN_NAVIGATION) |
| 272 LogAbortChainHistograms(nullptr); | 272 LogAbortChainHistograms(nullptr); |
| 273 | 273 |
| 274 for (const auto& observer : observers_) { | 274 for (const auto& observer : observers_) { |
| 275 observer->OnComplete(timing_, info); | 275 observer->OnComplete(timing_, info); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 322 } | 322 } |
| 323 | 323 |
| 324 void PageLoadTracker::WebContentsHidden() { | 324 void PageLoadTracker::WebContentsHidden() { |
| 325 // Only log the first time we background in a given page load. | 325 // Only log the first time we background in a given page load. |
| 326 if (background_time_.is_null()) { | 326 if (background_time_.is_null()) { |
| 327 // Make sure we either started in the foreground and haven't been | 327 // Make sure we either started in the foreground and haven't been |
| 328 // foregrounded yet, or started in the background and have already been | 328 // foregrounded yet, or started in the background and have already been |
| 329 // foregrounded. | 329 // foregrounded. |
| 330 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); | 330 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); |
| 331 background_time_ = base::TimeTicks::Now(); | 331 background_time_ = base::TimeTicks::Now(); |
| 332 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); |
| 332 } | 333 } |
| 333 | 334 |
| 334 for (const auto& observer : observers_) | 335 for (const auto& observer : observers_) |
| 335 observer->OnHidden(); | 336 observer->OnHidden(); |
| 336 } | 337 } |
| 337 | 338 |
| 338 void PageLoadTracker::WebContentsShown() { | 339 void PageLoadTracker::WebContentsShown() { |
| 339 // Only log the first time we foreground in a given page load. | 340 // Only log the first time we foreground in a given page load. |
| 340 if (foreground_time_.is_null()) { | 341 if (foreground_time_.is_null()) { |
| 341 // Make sure we either started in the background and haven't been | 342 // Make sure we either started in the background and haven't been |
| 342 // backgrounded yet, or started in the foreground and have already been | 343 // backgrounded yet, or started in the foreground and have already been |
| 343 // backgrounded. | 344 // backgrounded. |
| 344 DCHECK_NE(started_in_foreground_, background_time_.is_null()); | 345 DCHECK_NE(started_in_foreground_, background_time_.is_null()); |
| 345 foreground_time_ = base::TimeTicks::Now(); | 346 foreground_time_ = base::TimeTicks::Now(); |
| 347 ClampBrowserTimestampIfInterProcessTimeTickSkew(&foreground_time_); |
| 346 } | 348 } |
| 347 | 349 |
| 348 for (const auto& observer : observers_) | 350 for (const auto& observer : observers_) |
| 349 observer->OnShown(); | 351 observer->OnShown(); |
| 350 } | 352 } |
| 351 | 353 |
| 352 void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) { | 354 void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) { |
| 353 // TODO(bmcquade): To improve accuracy, consider adding commit time to | 355 // TODO(bmcquade): To improve accuracy, consider adding commit time to |
| 354 // NavigationHandle. Taking a timestamp here should be close enough for now. | 356 // NavigationHandle. Taking a timestamp here should be close enough for now. |
| 355 commit_time_ = base::TimeTicks::Now(); | 357 commit_time_ = base::TimeTicks::Now(); |
| 358 ClampBrowserTimestampIfInterProcessTimeTickSkew(&commit_time_); |
| 356 url_ = navigation_handle->GetURL(); | 359 url_ = navigation_handle->GetURL(); |
| 357 for (const auto& observer : observers_) { | 360 for (const auto& observer : observers_) { |
| 358 observer->OnCommit(navigation_handle); | 361 observer->OnCommit(navigation_handle); |
| 359 } | 362 } |
| 360 LogAbortChainHistograms(navigation_handle); | 363 LogAbortChainHistograms(navigation_handle); |
| 361 } | 364 } |
| 362 | 365 |
| 363 void PageLoadTracker::FailedProvisionalLoad( | 366 void PageLoadTracker::FailedProvisionalLoad( |
| 364 content::NavigationHandle* navigation_handle) { | 367 content::NavigationHandle* navigation_handle) { |
| 365 for (const auto& observer : observers_) { | 368 for (const auto& observer : observers_) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 396 valid_behavior_descendent) { | 399 valid_behavior_descendent) { |
| 397 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() | 400 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() |
| 398 // must be called before DispatchObserverTimingCallbacks, but its | 401 // must be called before DispatchObserverTimingCallbacks, but its |
| 399 // implementation depends on the state of metadata_, so we need to update | 402 // implementation depends on the state of metadata_, so we need to update |
| 400 // metadata_ before calling GetPageLoadMetricsInfo. Thus, we make a copy of | 403 // metadata_ before calling GetPageLoadMetricsInfo. Thus, we make a copy of |
| 401 // timing here, update timing_ and metadata_, and then proceed to dispatch | 404 // timing here, update timing_ and metadata_, and then proceed to dispatch |
| 402 // the observer timing callbacks. | 405 // the observer timing callbacks. |
| 403 const PageLoadTiming last_timing = timing_; | 406 const PageLoadTiming last_timing = timing_; |
| 404 timing_ = new_timing; | 407 timing_ = new_timing; |
| 405 metadata_ = new_metadata; | 408 metadata_ = new_metadata; |
| 406 const PageLoadExtraInfo info = GetPageLoadMetricsInfo(); | 409 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 407 for (const auto& observer : observers_) { | 410 for (const auto& observer : observers_) { |
| 408 DispatchObserverTimingCallbacks(observer.get(), last_timing, new_timing, | 411 DispatchObserverTimingCallbacks(observer.get(), last_timing, new_timing, |
| 409 info); | 412 info); |
| 410 } | 413 } |
| 411 return true; | 414 return true; |
| 412 } | 415 } |
| 413 return false; | 416 return false; |
| 414 } | 417 } |
| 415 | 418 |
| 416 void PageLoadTracker::set_renderer_tracked(bool renderer_tracked) { | 419 void PageLoadTracker::set_renderer_tracked(bool renderer_tracked) { |
| 417 renderer_tracked_ = renderer_tracked; | 420 renderer_tracked_ = renderer_tracked; |
| 418 } | 421 } |
| 419 | 422 |
| 420 void PageLoadTracker::AddObserver( | 423 void PageLoadTracker::AddObserver( |
| 421 std::unique_ptr<PageLoadMetricsObserver> observer) { | 424 std::unique_ptr<PageLoadMetricsObserver> observer) { |
| 422 observers_.push_back(std::move(observer)); | 425 observers_.push_back(std::move(observer)); |
| 423 } | 426 } |
| 424 | 427 |
| 425 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { | 428 void PageLoadTracker::ClampBrowserTimestampIfInterProcessTimeTickSkew( |
| 426 base::TimeDelta first_background_time; | 429 base::TimeTicks* event_time) { |
| 427 base::TimeDelta first_foreground_time; | 430 DCHECK(event_time != nullptr); |
| 428 base::TimeDelta time_to_abort; | 431 // Windows 10 GCE bot non-deterministically failed because TimeTicks::Now() |
| 429 base::TimeDelta time_to_commit; | 432 // called in the browser process e.g. commit_time was less than |
| 430 if (!background_time_.is_null()) | 433 // navigation_start_ that was populated in the renderer process because the |
| 434 // clock was not system-wide monotonic. |
| 435 // Note that navigation_start_ can also be set in the browser process in |
| 436 // some cases and in those cases event_time should never be < |
| 437 // navigation_start_. If it is due to a code error and it gets clamped in this |
| 438 // function, on high resolution systems it should lead to a dcheck failure. |
| 439 |
| 440 // TODO (shivanisha) Currently IsHighResolution is the best way to check |
| 441 // if the clock is system-wide monotonic. However IsHighResolution |
| 442 // does a broader check to see if the clock in use is high resolution |
| 443 // which also implies it is system-wide monotonic (on Windows). |
| 444 if (base::TimeTicks::IsHighResolution()) { |
| 445 DCHECK(event_time->is_null() || *event_time >= navigation_start_); |
| 446 return; |
| 447 } |
| 448 |
| 449 if (!event_time->is_null() && *event_time < navigation_start_) { |
| 450 RecordInternalError(ERR_INTER_PROCESS_TIME_TICK_SKEW); |
| 451 *event_time = navigation_start_; |
| 452 } |
| 453 } |
| 454 |
| 455 PageLoadExtraInfo PageLoadTracker::ComputePageLoadExtraInfo() { |
| 456 base::Optional<base::TimeDelta> first_background_time; |
| 457 base::Optional<base::TimeDelta> first_foreground_time; |
| 458 base::Optional<base::TimeDelta> time_to_abort; |
| 459 base::Optional<base::TimeDelta> time_to_commit; |
| 460 |
| 461 if (!background_time_.is_null()) { |
| 462 DCHECK_GE(background_time_, navigation_start_); |
| 431 first_background_time = background_time_ - navigation_start_; | 463 first_background_time = background_time_ - navigation_start_; |
| 432 if (!foreground_time_.is_null()) | 464 } |
| 465 |
| 466 if (!foreground_time_.is_null()) { |
| 467 DCHECK_GE(foreground_time_, navigation_start_); |
| 433 first_foreground_time = foreground_time_ - navigation_start_; | 468 first_foreground_time = foreground_time_ - navigation_start_; |
| 469 } |
| 470 |
| 434 if (abort_type_ != ABORT_NONE) { | 471 if (abort_type_ != ABORT_NONE) { |
| 435 DCHECK_GT(abort_time_, navigation_start_); | 472 DCHECK_GE(abort_time_, navigation_start_); |
| 436 time_to_abort = abort_time_ - navigation_start_; | 473 time_to_abort = abort_time_ - navigation_start_; |
| 437 } else { | 474 } else { |
| 438 DCHECK(abort_time_.is_null()); | 475 DCHECK(abort_time_.is_null()); |
| 439 } | 476 } |
| 440 | 477 |
| 441 if (!commit_time_.is_null()) { | 478 if (!commit_time_.is_null()) { |
| 442 DCHECK_GT(commit_time_, navigation_start_); | 479 DCHECK_GE(commit_time_, navigation_start_); |
| 443 time_to_commit = commit_time_ - navigation_start_; | 480 time_to_commit = commit_time_ - navigation_start_; |
| 444 } else { | |
| 445 DCHECK(commit_time_.is_null()); | |
| 446 } | 481 } |
| 482 |
| 447 return PageLoadExtraInfo( | 483 return PageLoadExtraInfo( |
| 448 first_background_time, first_foreground_time, started_in_foreground_, | 484 first_background_time, first_foreground_time, started_in_foreground_, |
| 449 commit_time_.is_null() ? GURL() : url_, time_to_commit, abort_type_, | 485 commit_time_.is_null() ? GURL() : url_, time_to_commit, abort_type_, |
| 450 time_to_abort, metadata_); | 486 time_to_abort, metadata_); |
| 451 } | 487 } |
| 452 | 488 |
| 453 void PageLoadTracker::NotifyAbort(UserAbortType abort_type, | 489 void PageLoadTracker::NotifyAbort(UserAbortType abort_type, |
| 454 base::TimeTicks timestamp) { | 490 base::TimeTicks timestamp, |
| 491 bool is_certainly_browser_timestamp) { |
| 455 DCHECK_NE(abort_type, ABORT_NONE); | 492 DCHECK_NE(abort_type, ABORT_NONE); |
| 456 // Use UpdateAbort to update an already notified PageLoadTracker. | 493 // Use UpdateAbort to update an already notified PageLoadTracker. |
| 457 if (abort_type_ != ABORT_NONE) | 494 if (abort_type_ != ABORT_NONE) |
| 458 return; | 495 return; |
| 459 | 496 |
| 460 UpdateAbortInternal(abort_type, timestamp); | 497 UpdateAbortInternal(abort_type, timestamp, is_certainly_browser_timestamp); |
| 461 } | 498 } |
| 462 | 499 |
| 463 void PageLoadTracker::UpdateAbort(UserAbortType abort_type, | 500 void PageLoadTracker::UpdateAbort(UserAbortType abort_type, |
| 464 base::TimeTicks timestamp) { | 501 base::TimeTicks timestamp, |
| 502 bool is_certainly_browser_timestamp) { |
| 465 DCHECK_NE(abort_type, ABORT_NONE); | 503 DCHECK_NE(abort_type, ABORT_NONE); |
| 466 DCHECK_NE(abort_type, ABORT_OTHER); | 504 DCHECK_NE(abort_type, ABORT_OTHER); |
| 467 DCHECK_EQ(abort_type_, ABORT_OTHER); | 505 DCHECK_EQ(abort_type_, ABORT_OTHER); |
| 468 | 506 |
| 469 // For some aborts (e.g. navigations), the initiated timestamp can be earlier | 507 // For some aborts (e.g. navigations), the initiated timestamp can be earlier |
| 470 // than the timestamp that aborted the load. Taking the minimum gives the | 508 // than the timestamp that aborted the load. Taking the minimum gives the |
| 471 // closest user initiated time known. | 509 // closest user initiated time known. |
| 472 UpdateAbortInternal(abort_type, std::min(abort_time_, timestamp)); | 510 UpdateAbortInternal(abort_type, std::min(abort_time_, timestamp), |
| 511 is_certainly_browser_timestamp); |
| 473 } | 512 } |
| 474 | 513 |
| 475 bool PageLoadTracker::IsLikelyProvisionalAbort( | 514 bool PageLoadTracker::IsLikelyProvisionalAbort( |
| 476 base::TimeTicks abort_cause_time) { | 515 base::TimeTicks abort_cause_time) { |
| 477 // Note that |abort_cause_time - abort_time| can be negative. | 516 // Note that |abort_cause_time - abort_time| can be negative. |
| 478 return abort_type_ == ABORT_OTHER && | 517 return abort_type_ == ABORT_OTHER && |
| 479 (abort_cause_time - abort_time_).InMilliseconds() < 100; | 518 (abort_cause_time - abort_time_).InMilliseconds() < 100; |
| 480 } | 519 } |
| 481 | 520 |
| 482 bool PageLoadTracker::MatchesOriginalNavigation( | 521 bool PageLoadTracker::MatchesOriginalNavigation( |
| 483 content::NavigationHandle* navigation_handle) { | 522 content::NavigationHandle* navigation_handle) { |
| 484 // Neither navigation should have committed. | 523 // Neither navigation should have committed. |
| 485 DCHECK(!navigation_handle->HasCommitted()); | 524 DCHECK(!navigation_handle->HasCommitted()); |
| 486 DCHECK(commit_time_.is_null()); | 525 DCHECK(commit_time_.is_null()); |
| 487 return navigation_handle->GetURL() == url_; | 526 return navigation_handle->GetURL() == url_; |
| 488 } | 527 } |
| 489 | 528 |
| 490 void PageLoadTracker::UpdateAbortInternal(UserAbortType abort_type, | 529 void PageLoadTracker::UpdateAbortInternal(UserAbortType abort_type, |
| 491 base::TimeTicks timestamp) { | 530 base::TimeTicks timestamp, |
| 531 bool is_certainly_browser_timestamp) { |
| 492 // When a provisional navigation commits, that navigation's start time is | 532 // When a provisional navigation commits, that navigation's start time is |
| 493 // interpreted as the abort time for other provisional loads in the tab. | 533 // interpreted as the abort time for other provisional loads in the tab. |
| 494 // However, this only makes sense if the committed load started after the | 534 // However, this only makes sense if the committed load started after the |
| 495 // aborted provisional loads started. Thus we ignore cases where the committed | 535 // aborted provisional loads started. Thus we ignore cases where the committed |
| 496 // load started before the aborted provisional load, as this would result in | 536 // load started before the aborted provisional load, as this would result in |
| 497 // recording a negative time-to-abort. The real issue here is that we have to | 537 // recording a negative time-to-abort. The real issue here is that we have to |
| 498 // infer the cause of aborts. It would be better if the navigation code could | 538 // infer the cause of aborts. It would be better if the navigation code could |
| 499 // instead report the actual cause of an aborted navigation. See crbug/571647 | 539 // instead report the actual cause of an aborted navigation. See crbug/571647 |
| 500 // for details. | 540 // for details. |
| 501 if (timestamp <= navigation_start_) { | 541 if (timestamp < navigation_start_) { |
| 502 RecordInternalError(ERR_ABORT_BEFORE_NAVIGATION_START); | 542 RecordInternalError(ERR_ABORT_BEFORE_NAVIGATION_START); |
| 503 abort_type_ = ABORT_NONE; | 543 abort_type_ = ABORT_NONE; |
| 504 abort_time_ = base::TimeTicks(); | 544 abort_time_ = base::TimeTicks(); |
| 505 return; | 545 return; |
| 506 } | 546 } |
| 507 abort_type_ = abort_type; | 547 abort_type_ = abort_type; |
| 508 abort_time_ = timestamp; | 548 abort_time_ = timestamp; |
| 549 |
| 550 if (is_certainly_browser_timestamp) { |
| 551 ClampBrowserTimestampIfInterProcessTimeTickSkew(&abort_time_); |
| 552 } |
| 509 } | 553 } |
| 510 | 554 |
| 511 // static | 555 // static |
| 512 MetricsWebContentsObserver::MetricsWebContentsObserver( | 556 MetricsWebContentsObserver::MetricsWebContentsObserver( |
| 513 content::WebContents* web_contents, | 557 content::WebContents* web_contents, |
| 514 std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface) | 558 std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface) |
| 515 : content::WebContentsObserver(web_contents), | 559 : content::WebContentsObserver(web_contents), |
| 516 in_foreground_(false), | 560 in_foreground_(false), |
| 517 embedder_interface_(std::move(embedder_interface)), | 561 embedder_interface_(std::move(embedder_interface)), |
| 518 has_navigated_(false) { | 562 has_navigated_(false) { |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 // the MetricsWebContentsObserver owns them both list and they are torn down | 659 // the MetricsWebContentsObserver owns them both list and they are torn down |
| 616 // after the PageLoadTracker. The PageLoadTracker does not hold on to | 660 // after the PageLoadTracker. The PageLoadTracker does not hold on to |
| 617 // committed_load_ or navigation_handle beyond the scope of the constructor. | 661 // committed_load_ or navigation_handle beyond the scope of the constructor. |
| 618 provisional_loads_.insert(std::make_pair( | 662 provisional_loads_.insert(std::make_pair( |
| 619 navigation_handle, | 663 navigation_handle, |
| 620 base::WrapUnique(new PageLoadTracker( | 664 base::WrapUnique(new PageLoadTracker( |
| 621 in_foreground_, embedder_interface_.get(), currently_committed_url, | 665 in_foreground_, embedder_interface_.get(), currently_committed_url, |
| 622 navigation_handle, chain_size, chain_size_same_url)))); | 666 navigation_handle, chain_size, chain_size_same_url)))); |
| 623 } | 667 } |
| 624 | 668 |
| 669 const PageLoadExtraInfo |
| 670 MetricsWebContentsObserver::GetPageLoadExtraInfoForCommittedLoad() { |
| 671 DCHECK(committed_load_); |
| 672 return committed_load_->ComputePageLoadExtraInfo(); |
| 673 } |
| 674 |
| 625 void MetricsWebContentsObserver::DidFinishNavigation( | 675 void MetricsWebContentsObserver::DidFinishNavigation( |
| 626 content::NavigationHandle* navigation_handle) { | 676 content::NavigationHandle* navigation_handle) { |
| 627 if (!navigation_handle->IsInMainFrame()) | 677 if (!navigation_handle->IsInMainFrame()) |
| 628 return; | 678 return; |
| 629 | 679 |
| 630 std::unique_ptr<PageLoadTracker> finished_nav( | 680 std::unique_ptr<PageLoadTracker> finished_nav( |
| 631 std::move(provisional_loads_[navigation_handle])); | 681 std::move(provisional_loads_[navigation_handle])); |
| 632 provisional_loads_.erase(navigation_handle); | 682 provisional_loads_.erase(navigation_handle); |
| 633 | 683 |
| 634 // There's a chance a navigation could have started before we were added to a | 684 // There's a chance a navigation could have started before we were added to a |
| (...skipping 12 matching lines...) Expand all Loading... |
| 647 net::Error error = navigation_handle->GetNetErrorCode(); | 697 net::Error error = navigation_handle->GetNetErrorCode(); |
| 648 | 698 |
| 649 // net::OK: This case occurs when the NavigationHandle finishes and reports | 699 // net::OK: This case occurs when the NavigationHandle finishes and reports |
| 650 // !HasCommitted(), but reports no net::Error. This should not occur | 700 // !HasCommitted(), but reports no net::Error. This should not occur |
| 651 // pre-PlzNavigate, but afterwards it should represent the navigation | 701 // pre-PlzNavigate, but afterwards it should represent the navigation |
| 652 // stopped by the user before it was ready to commit. | 702 // stopped by the user before it was ready to commit. |
| 653 // net::ERR_ABORTED: An aborted provisional load has error net::ERR_ABORTED. | 703 // net::ERR_ABORTED: An aborted provisional load has error net::ERR_ABORTED. |
| 654 // Note that this can come from some non user-initiated errors, such as | 704 // Note that this can come from some non user-initiated errors, such as |
| 655 // downloads, or 204 responses. See crbug.com/542369. | 705 // downloads, or 204 responses. See crbug.com/542369. |
| 656 if ((error == net::OK) || (error == net::ERR_ABORTED)) { | 706 if ((error == net::OK) || (error == net::ERR_ABORTED)) { |
| 657 finished_nav->NotifyAbort(ABORT_OTHER, base::TimeTicks::Now()); | 707 finished_nav->NotifyAbort(ABORT_OTHER, base::TimeTicks::Now(), true); |
| 658 aborted_provisional_loads_.push_back(std::move(finished_nav)); | 708 aborted_provisional_loads_.push_back(std::move(finished_nav)); |
| 659 } | 709 } |
| 660 | 710 |
| 661 return; | 711 return; |
| 662 } | 712 } |
| 663 | 713 |
| 664 // Don't treat a same-page nav as a new page load. | 714 // Don't treat a same-page nav as a new page load. |
| 665 if (navigation_handle->IsSamePage()) | 715 if (navigation_handle->IsSamePage()) |
| 666 return; | 716 return; |
| 667 | 717 |
| 668 // Notify other loads that they may have been aborted by this committed load. | 718 // Notify other loads that they may have been aborted by this committed load. |
| 669 // Note that by using the committed navigation start as the abort cause, we | 719 // Note that by using the committed navigation start as the abort cause, we |
| 670 // lose data on provisional loads that were aborted by other provisional | 720 // lose data on provisional loads that were aborted by other provisional |
| 671 // loads. Those will either be listed as ABORT_OTHER or as being aborted by | 721 // loads. Those will either be listed as ABORT_OTHER or as being aborted by |
| 672 // this load. | 722 // this load. |
| 723 // is_certainly_browser_timestamp is set to false because NavigationStart() |
| 724 // could be set in either the renderer or browser process. |
| 673 NotifyAbortAllLoadsWithTimestamp( | 725 NotifyAbortAllLoadsWithTimestamp( |
| 674 AbortTypeForPageTransition(navigation_handle->GetPageTransition()), | 726 AbortTypeForPageTransition(navigation_handle->GetPageTransition()), |
| 675 navigation_handle->NavigationStart()); | 727 navigation_handle->NavigationStart(), false); |
| 676 | 728 |
| 677 committed_load_ = std::move(finished_nav); | 729 committed_load_ = std::move(finished_nav); |
| 678 aborted_provisional_loads_.clear(); | 730 aborted_provisional_loads_.clear(); |
| 679 | 731 |
| 680 const GURL& browser_url = web_contents()->GetLastCommittedURL(); | 732 const GURL& browser_url = web_contents()->GetLastCommittedURL(); |
| 681 const std::string& mime_type = web_contents()->GetContentsMimeType(); | 733 const std::string& mime_type = web_contents()->GetContentsMimeType(); |
| 682 DCHECK(!browser_url.is_empty()); | 734 DCHECK(!browser_url.is_empty()); |
| 683 DCHECK(!mime_type.empty()); | 735 DCHECK(!mime_type.empty()); |
| 684 committed_load_->set_renderer_tracked( | 736 committed_load_->set_renderer_tracked( |
| 685 IsRelevantNavigation(navigation_handle, browser_url, mime_type)); | 737 IsRelevantNavigation(navigation_handle, browser_url, mime_type)); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 752 } | 804 } |
| 753 | 805 |
| 754 // If this is a crash, eagerly log the aborted provisional loads and the | 806 // If this is a crash, eagerly log the aborted provisional loads and the |
| 755 // committed load. |provisional_loads_| don't need to be destroyed here | 807 // committed load. |provisional_loads_| don't need to be destroyed here |
| 756 // because their lifetime is tied to the NavigationHandle. | 808 // because their lifetime is tied to the NavigationHandle. |
| 757 committed_load_.reset(); | 809 committed_load_.reset(); |
| 758 aborted_provisional_loads_.clear(); | 810 aborted_provisional_loads_.clear(); |
| 759 } | 811 } |
| 760 | 812 |
| 761 void MetricsWebContentsObserver::NotifyAbortAllLoads(UserAbortType abort_type) { | 813 void MetricsWebContentsObserver::NotifyAbortAllLoads(UserAbortType abort_type) { |
| 762 NotifyAbortAllLoadsWithTimestamp(abort_type, base::TimeTicks::Now()); | 814 NotifyAbortAllLoadsWithTimestamp(abort_type, base::TimeTicks::Now(), true); |
| 763 } | 815 } |
| 764 | 816 |
| 765 void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp( | 817 void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp( |
| 766 UserAbortType abort_type, | 818 UserAbortType abort_type, |
| 767 base::TimeTicks timestamp) { | 819 base::TimeTicks timestamp, |
| 820 bool is_certainly_browser_timestamp) { |
| 768 if (committed_load_) | 821 if (committed_load_) |
| 769 committed_load_->NotifyAbort(abort_type, timestamp); | 822 committed_load_->NotifyAbort(abort_type, timestamp, |
| 823 is_certainly_browser_timestamp); |
| 770 for (const auto& kv : provisional_loads_) { | 824 for (const auto& kv : provisional_loads_) { |
| 771 kv.second->NotifyAbort(abort_type, timestamp); | 825 kv.second->NotifyAbort(abort_type, timestamp, |
| 826 is_certainly_browser_timestamp); |
| 772 } | 827 } |
| 773 for (const auto& tracker : aborted_provisional_loads_) { | 828 for (const auto& tracker : aborted_provisional_loads_) { |
| 774 if (tracker->IsLikelyProvisionalAbort(timestamp)) | 829 if (tracker->IsLikelyProvisionalAbort(timestamp)) |
| 775 tracker->UpdateAbort(abort_type, timestamp); | 830 tracker->UpdateAbort(abort_type, timestamp, |
| 831 is_certainly_browser_timestamp); |
| 776 } | 832 } |
| 777 aborted_provisional_loads_.clear(); | 833 aborted_provisional_loads_.clear(); |
| 778 } | 834 } |
| 779 | 835 |
| 780 std::unique_ptr<PageLoadTracker> | 836 std::unique_ptr<PageLoadTracker> |
| 781 MetricsWebContentsObserver::NotifyAbortedProvisionalLoadsNewNavigation( | 837 MetricsWebContentsObserver::NotifyAbortedProvisionalLoadsNewNavigation( |
| 782 content::NavigationHandle* new_navigation) { | 838 content::NavigationHandle* new_navigation) { |
| 783 // If there are multiple aborted loads that can be attributed to this one, | 839 // If there are multiple aborted loads that can be attributed to this one, |
| 784 // just count the latest one for simplicity. Other loads will fall into the | 840 // just count the latest one for simplicity. Other loads will fall into the |
| 785 // OTHER bucket, though there shouldn't be very many. | 841 // OTHER bucket, though there shouldn't be very many. |
| 786 if (aborted_provisional_loads_.size() == 0) | 842 if (aborted_provisional_loads_.size() == 0) |
| 787 return nullptr; | 843 return nullptr; |
| 788 if (aborted_provisional_loads_.size() > 1) | 844 if (aborted_provisional_loads_.size() > 1) |
| 789 RecordInternalError(ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS); | 845 RecordInternalError(ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS); |
| 790 | 846 |
| 791 std::unique_ptr<PageLoadTracker> last_aborted_load = | 847 std::unique_ptr<PageLoadTracker> last_aborted_load = |
| 792 std::move(aborted_provisional_loads_.back()); | 848 std::move(aborted_provisional_loads_.back()); |
| 793 aborted_provisional_loads_.pop_back(); | 849 aborted_provisional_loads_.pop_back(); |
| 794 | 850 |
| 795 base::TimeTicks timestamp = new_navigation->NavigationStart(); | 851 base::TimeTicks timestamp = new_navigation->NavigationStart(); |
| 796 if (last_aborted_load->IsLikelyProvisionalAbort(timestamp)) | 852 if (last_aborted_load->IsLikelyProvisionalAbort(timestamp)) |
| 797 last_aborted_load->UpdateAbort(ABORT_UNKNOWN_NAVIGATION, timestamp); | 853 last_aborted_load->UpdateAbort(ABORT_UNKNOWN_NAVIGATION, timestamp, false); |
| 798 | 854 |
| 799 aborted_provisional_loads_.clear(); | 855 aborted_provisional_loads_.clear(); |
| 800 return last_aborted_load; | 856 return last_aborted_load; |
| 801 } | 857 } |
| 802 | 858 |
| 803 void MetricsWebContentsObserver::OnTimingUpdated( | 859 void MetricsWebContentsObserver::OnTimingUpdated( |
| 804 content::RenderFrameHost* render_frame_host, | 860 content::RenderFrameHost* render_frame_host, |
| 805 const PageLoadTiming& timing, | 861 const PageLoadTiming& timing, |
| 806 const PageLoadMetadata& metadata) { | 862 const PageLoadMetadata& metadata) { |
| 807 bool error = false; | 863 bool error = false; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 830 | 886 |
| 831 if (!committed_load_->UpdateTiming(timing, metadata)) { | 887 if (!committed_load_->UpdateTiming(timing, metadata)) { |
| 832 // If the page load tracker cannot update its timing, something is wrong | 888 // If the page load tracker cannot update its timing, something is wrong |
| 833 // with the IPC (it's from another load, or it's invalid in some other way). | 889 // with the IPC (it's from another load, or it's invalid in some other way). |
| 834 // We expect this to be a rare occurrence. | 890 // We expect this to be a rare occurrence. |
| 835 RecordInternalError(ERR_BAD_TIMING_IPC); | 891 RecordInternalError(ERR_BAD_TIMING_IPC); |
| 836 } | 892 } |
| 837 } | 893 } |
| 838 | 894 |
| 839 } // namespace page_load_metrics | 895 } // namespace page_load_metrics |
| OLD | NEW |