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