| OLD | NEW |
| 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> |
| 11 | 11 |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
| 14 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 15 #include "chrome/browser/page_load_metrics/browser_page_track_decider.h" |
| 15 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.
h" | 16 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.
h" |
| 16 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" | 17 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" |
| 17 #include "chrome/browser/prerender/prerender_contents.h" | 18 #include "chrome/browser/prerender/prerender_contents.h" |
| 18 #include "chrome/common/page_load_metrics/page_load_timing.h" | 19 #include "chrome/common/page_load_metrics/page_load_timing.h" |
| 19 #include "content/public/browser/navigation_details.h" | 20 #include "content/public/browser/navigation_details.h" |
| 20 #include "content/public/browser/navigation_handle.h" | 21 #include "content/public/browser/navigation_handle.h" |
| 22 #include "content/public/browser/render_frame_host.h" |
| 21 #include "content/public/browser/web_contents.h" | 23 #include "content/public/browser/web_contents.h" |
| 22 #include "content/public/browser/web_contents_observer.h" | 24 #include "content/public/browser/web_contents_observer.h" |
| 23 #include "content/public/common/browser_side_navigation_policy.h" | 25 #include "content/public/common/browser_side_navigation_policy.h" |
| 24 #include "ui/base/page_transition_types.h" | 26 #include "ui/base/page_transition_types.h" |
| 25 | 27 |
| 26 // This macro invokes the specified method on each observer, passing the | 28 // This macro invokes the specified method on each observer, passing the |
| 27 // variable length arguments as the method's arguments, and removes the observer | 29 // variable length arguments as the method's arguments, and removes the observer |
| 28 // from the list of observers if the given method returns STOP_OBSERVING. | 30 // from the list of observers if the given method returns STOP_OBSERVING. |
| 29 #define INVOKE_AND_PRUNE_OBSERVERS(observers, Method, ...) \ | 31 #define INVOKE_AND_PRUNE_OBSERVERS(observers, Method, ...) \ |
| 30 for (auto it = observers.begin(); it != observers.end();) { \ | 32 for (auto it = observers.begin(); it != observers.end();) { \ |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 timing.paint_timing.first_meaningful_paint)) { | 272 timing.paint_timing.first_meaningful_paint)) { |
| 271 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint | 273 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint |
| 272 << " for first_meaningful_paint " | 274 << " for first_meaningful_paint " |
| 273 << timing.paint_timing.first_meaningful_paint; | 275 << timing.paint_timing.first_meaningful_paint; |
| 274 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; | 276 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; |
| 275 } | 277 } |
| 276 | 278 |
| 277 return internal::VALID; | 279 return internal::VALID; |
| 278 } | 280 } |
| 279 | 281 |
| 282 // Updates *|inout_existing_value| with |optional_candidate_new_value|, if |
| 283 // either *|inout_existing_value| isn't set, or |optional_candidate_new_value| < |
| 284 // |inout_existing_value|. |
| 285 void MaybeUpdateTimeDelta( |
| 286 base::Optional<base::TimeDelta>* inout_existing_value, |
| 287 base::TimeDelta navigation_start_offset, |
| 288 const base::Optional<base::TimeDelta>& optional_candidate_new_value) { |
| 289 // If we don't get a new value, there's nothing to do |
| 290 if (!optional_candidate_new_value) |
| 291 return; |
| 292 |
| 293 // optional_candidate_new_value is relative to navigation start in its |
| 294 // frame. We need to adjust it to be relative to navigation start in the main |
| 295 // frame, so offset it by navigation_start_offset. |
| 296 base::TimeDelta candidate_new_value = |
| 297 navigation_start_offset + optional_candidate_new_value.value(); |
| 298 |
| 299 if (*inout_existing_value) { |
| 300 // If we have a new value, but it is after the existing value, then keep the |
| 301 // existing value. |
| 302 if (*inout_existing_value <= candidate_new_value) |
| 303 return; |
| 304 |
| 305 // We received a new timing event, but with a timestamp before the timestamp |
| 306 // of a timing update we had received previously. We expect this to happen |
| 307 // occasionally, as inter-frame updates can arrive out of order. Record a |
| 308 // histogram to track how frequently it happens, along with the magnitude |
| 309 // of the delta. |
| 310 PAGE_LOAD_HISTOGRAM("PageLoad.Internal.OutOfOrderInterFrameTiming", |
| 311 inout_existing_value->value() - candidate_new_value); |
| 312 } |
| 313 |
| 314 *inout_existing_value = candidate_new_value; |
| 315 } |
| 316 |
| 280 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { | 317 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { |
| 281 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, | 318 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, |
| 282 completed_after_background); | 319 completed_after_background); |
| 283 } | 320 } |
| 284 | 321 |
| 285 void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer, | 322 void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer, |
| 286 const PageLoadTiming& last_timing, | 323 const PageLoadTiming& last_timing, |
| 287 const PageLoadTiming& new_timing, | 324 const PageLoadTiming& new_timing, |
| 288 const PageLoadMetadata& last_metadata, | 325 const PageLoadMetadata& last_metadata, |
| 289 const PageLoadExtraInfo& extra_info) { | 326 const PageLoadExtraInfo& extra_info) { |
| 290 if (extra_info.main_frame_metadata.behavior_flags != | 327 if (extra_info.main_frame_metadata.behavior_flags != |
| 291 last_metadata.behavior_flags) | 328 last_metadata.behavior_flags) |
| 292 observer->OnLoadingBehaviorObserved(extra_info); | 329 observer->OnLoadingBehaviorObserved(extra_info); |
| 293 if (last_timing != new_timing) | 330 if (last_timing != new_timing) |
| 294 observer->OnTimingUpdate(new_timing, extra_info); | 331 observer->OnTimingUpdate(new_timing, extra_info); |
| 295 if (new_timing.document_timing.dom_content_loaded_event_start && | 332 if (new_timing.document_timing.dom_content_loaded_event_start && |
| 296 !last_timing.document_timing.dom_content_loaded_event_start) | 333 !last_timing.document_timing.dom_content_loaded_event_start) |
| 297 observer->OnDomContentLoadedEventStart(new_timing, extra_info); | 334 observer->OnDomContentLoadedEventStart(new_timing, extra_info); |
| 298 if (new_timing.document_timing.load_event_start && | 335 if (new_timing.document_timing.load_event_start && |
| 299 !last_timing.document_timing.load_event_start) | 336 !last_timing.document_timing.load_event_start) |
| 300 observer->OnLoadEventStart(new_timing, extra_info); | 337 observer->OnLoadEventStart(new_timing, extra_info); |
| 301 if (new_timing.document_timing.first_layout && | 338 if (new_timing.document_timing.first_layout && |
| 302 !last_timing.document_timing.first_layout) | 339 !last_timing.document_timing.first_layout) |
| 303 observer->OnFirstLayout(new_timing, extra_info); | 340 observer->OnFirstLayout(new_timing, extra_info); |
| 304 if (new_timing.paint_timing.first_paint && | 341 if (new_timing.paint_timing.first_paint && |
| 305 !last_timing.paint_timing.first_paint) | 342 !last_timing.paint_timing.first_paint) |
| 306 observer->OnFirstPaint(new_timing, extra_info); | 343 observer->OnFirstPaintInPage(new_timing, extra_info); |
| 307 if (new_timing.paint_timing.first_text_paint && | 344 if (new_timing.paint_timing.first_text_paint && |
| 308 !last_timing.paint_timing.first_text_paint) | 345 !last_timing.paint_timing.first_text_paint) |
| 309 observer->OnFirstTextPaint(new_timing, extra_info); | 346 observer->OnFirstTextPaintInPage(new_timing, extra_info); |
| 310 if (new_timing.paint_timing.first_image_paint && | 347 if (new_timing.paint_timing.first_image_paint && |
| 311 !last_timing.paint_timing.first_image_paint) | 348 !last_timing.paint_timing.first_image_paint) |
| 312 observer->OnFirstImagePaint(new_timing, extra_info); | 349 observer->OnFirstImagePaintInPage(new_timing, extra_info); |
| 313 if (new_timing.paint_timing.first_contentful_paint && | 350 if (new_timing.paint_timing.first_contentful_paint && |
| 314 !last_timing.paint_timing.first_contentful_paint) | 351 !last_timing.paint_timing.first_contentful_paint) |
| 315 observer->OnFirstContentfulPaint(new_timing, extra_info); | 352 observer->OnFirstContentfulPaintInPage(new_timing, extra_info); |
| 316 if (new_timing.paint_timing.first_meaningful_paint && | 353 if (new_timing.paint_timing.first_meaningful_paint && |
| 317 !last_timing.paint_timing.first_meaningful_paint) | 354 !last_timing.paint_timing.first_meaningful_paint) |
| 318 observer->OnFirstMeaningfulPaint(new_timing, extra_info); | 355 observer->OnFirstMeaningfulPaintInMainFrameDocument(new_timing, extra_info); |
| 319 if (new_timing.parse_timing.parse_start && | 356 if (new_timing.parse_timing.parse_start && |
| 320 !last_timing.parse_timing.parse_start) | 357 !last_timing.parse_timing.parse_start) |
| 321 observer->OnParseStart(new_timing, extra_info); | 358 observer->OnParseStart(new_timing, extra_info); |
| 322 if (new_timing.parse_timing.parse_stop && | 359 if (new_timing.parse_timing.parse_stop && |
| 323 !last_timing.parse_timing.parse_stop) | 360 !last_timing.parse_timing.parse_stop) |
| 324 observer->OnParseStop(new_timing, extra_info); | 361 observer->OnParseStop(new_timing, extra_info); |
| 325 } | 362 } |
| 326 | 363 |
| 327 } // namespace | 364 } // namespace |
| 328 | 365 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 if (!failed_provisional_load_info_) | 420 if (!failed_provisional_load_info_) |
| 384 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); | 421 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); |
| 385 | 422 |
| 386 // Don't include any aborts that resulted in a new navigation, as the chain | 423 // Don't include any aborts that resulted in a new navigation, as the chain |
| 387 // length will be included in the aborter PageLoadTracker. | 424 // length will be included in the aborter PageLoadTracker. |
| 388 if (page_end_reason_ != END_RELOAD && | 425 if (page_end_reason_ != END_RELOAD && |
| 389 page_end_reason_ != END_FORWARD_BACK && | 426 page_end_reason_ != END_FORWARD_BACK && |
| 390 page_end_reason_ != END_NEW_NAVIGATION) { | 427 page_end_reason_ != END_NEW_NAVIGATION) { |
| 391 LogAbortChainHistograms(nullptr); | 428 LogAbortChainHistograms(nullptr); |
| 392 } | 429 } |
| 393 } else if (timing_.IsEmpty()) { | 430 } else if (merged_page_timing_.IsEmpty()) { |
| 394 RecordInternalError(ERR_NO_IPCS_RECEIVED); | 431 RecordInternalError(ERR_NO_IPCS_RECEIVED); |
| 395 } | 432 } |
| 396 | 433 |
| 397 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 434 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 398 for (const auto& observer : observers_) { | 435 for (const auto& observer : observers_) { |
| 399 if (failed_provisional_load_info_) { | 436 if (failed_provisional_load_info_) { |
| 400 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); | 437 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); |
| 401 } else if (did_commit_) { | 438 } else if (did_commit_) { |
| 402 observer->OnComplete(timing_, info); | 439 observer->OnComplete(merged_page_timing_, info); |
| 403 } | 440 } |
| 404 } | 441 } |
| 405 } | 442 } |
| 406 | 443 |
| 407 void PageLoadTracker::LogAbortChainHistograms( | 444 void PageLoadTracker::LogAbortChainHistograms( |
| 408 content::NavigationHandle* final_navigation) { | 445 content::NavigationHandle* final_navigation) { |
| 409 if (aborted_chain_size_ == 0) | 446 if (aborted_chain_size_ == 0) |
| 410 return; | 447 return; |
| 411 // Note that this could be broken out by this navigation's abort type, if more | 448 // Note that this could be broken out by this navigation's abort type, if more |
| 412 // granularity is needed. Add one to the chain size to count the current | 449 // granularity is needed. Add one to the chain size to count the current |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 // Only log the first time we background in a given page load. | 496 // Only log the first time we background in a given page load. |
| 460 if (background_time_.is_null()) { | 497 if (background_time_.is_null()) { |
| 461 // Make sure we either started in the foreground and haven't been | 498 // Make sure we either started in the foreground and haven't been |
| 462 // foregrounded yet, or started in the background and have already been | 499 // foregrounded yet, or started in the background and have already been |
| 463 // foregrounded. | 500 // foregrounded. |
| 464 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); | 501 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); |
| 465 background_time_ = base::TimeTicks::Now(); | 502 background_time_ = base::TimeTicks::Now(); |
| 466 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); | 503 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); |
| 467 } | 504 } |
| 468 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 505 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 469 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, timing_, info); | 506 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, merged_page_timing_, info); |
| 470 } | 507 } |
| 471 | 508 |
| 472 void PageLoadTracker::WebContentsShown() { | 509 void PageLoadTracker::WebContentsShown() { |
| 473 // Only log the first time we foreground in a given page load. | 510 // Only log the first time we foreground in a given page load. |
| 474 if (foreground_time_.is_null()) { | 511 if (foreground_time_.is_null()) { |
| 475 // Make sure we either started in the background and haven't been | 512 // Make sure we either started in the background and haven't been |
| 476 // backgrounded yet, or started in the foreground and have already been | 513 // backgrounded yet, or started in the foreground and have already been |
| 477 // backgrounded. | 514 // backgrounded. |
| 478 DCHECK_NE(started_in_foreground_, background_time_.is_null()); | 515 DCHECK_NE(started_in_foreground_, background_time_.is_null()); |
| 479 foreground_time_ = base::TimeTicks::Now(); | 516 foreground_time_ = base::TimeTicks::Now(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 navigation_handle->GetWebContents()->GetContentsMimeType()); | 548 navigation_handle->GetWebContents()->GetContentsMimeType()); |
| 512 | 549 |
| 513 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnCommit, navigation_handle); | 550 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnCommit, navigation_handle); |
| 514 LogAbortChainHistograms(navigation_handle); | 551 LogAbortChainHistograms(navigation_handle); |
| 515 } | 552 } |
| 516 | 553 |
| 517 void PageLoadTracker::DidFinishSubFrameNavigation( | 554 void PageLoadTracker::DidFinishSubFrameNavigation( |
| 518 content::NavigationHandle* navigation_handle) { | 555 content::NavigationHandle* navigation_handle) { |
| 519 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnDidFinishSubFrameNavigation, | 556 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnDidFinishSubFrameNavigation, |
| 520 navigation_handle); | 557 navigation_handle); |
| 558 |
| 559 if (!navigation_handle->HasCommitted()) |
| 560 return; |
| 561 |
| 562 // We have a new committed navigation, so discard information about the |
| 563 // previously committed navigation. |
| 564 subframe_navigation_start_offset_.erase( |
| 565 navigation_handle->GetFrameTreeNodeId()); |
| 566 |
| 567 BrowserPageTrackDecider decider(embedder_interface_, |
| 568 navigation_handle->GetWebContents(), |
| 569 navigation_handle); |
| 570 if (!decider.ShouldTrack()) |
| 571 return; |
| 572 |
| 573 if (navigation_start_ > navigation_handle->NavigationStart()) { |
| 574 RecordInternalError(ERR_SUBFRAME_NAVIGATION_START_BEFORE_MAIN_FRAME); |
| 575 return; |
| 576 } |
| 577 base::TimeDelta navigation_delta = |
| 578 navigation_handle->NavigationStart() - navigation_start_; |
| 579 subframe_navigation_start_offset_.insert(std::make_pair( |
| 580 navigation_handle->GetFrameTreeNodeId(), navigation_delta)); |
| 521 } | 581 } |
| 522 | 582 |
| 523 void PageLoadTracker::FailedProvisionalLoad( | 583 void PageLoadTracker::FailedProvisionalLoad( |
| 524 content::NavigationHandle* navigation_handle, | 584 content::NavigationHandle* navigation_handle, |
| 525 base::TimeTicks failed_load_time) { | 585 base::TimeTicks failed_load_time) { |
| 526 DCHECK(!failed_provisional_load_info_); | 586 DCHECK(!failed_provisional_load_info_); |
| 527 failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo( | 587 failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo( |
| 528 failed_load_time - navigation_handle->NavigationStart(), | 588 failed_load_time - navigation_handle->NavigationStart(), |
| 529 navigation_handle->GetNetErrorCode())); | 589 navigation_handle->GetNetErrorCode())); |
| 530 } | 590 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 542 } | 602 } |
| 543 | 603 |
| 544 void PageLoadTracker::FlushMetricsOnAppEnterBackground() { | 604 void PageLoadTracker::FlushMetricsOnAppEnterBackground() { |
| 545 if (!app_entered_background_) { | 605 if (!app_entered_background_) { |
| 546 RecordAppBackgroundPageLoadCompleted(false); | 606 RecordAppBackgroundPageLoadCompleted(false); |
| 547 app_entered_background_ = true; | 607 app_entered_background_ = true; |
| 548 } | 608 } |
| 549 | 609 |
| 550 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 610 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 551 INVOKE_AND_PRUNE_OBSERVERS(observers_, FlushMetricsOnAppEnterBackground, | 611 INVOKE_AND_PRUNE_OBSERVERS(observers_, FlushMetricsOnAppEnterBackground, |
| 552 timing_, info); | 612 merged_page_timing_, info); |
| 553 } | 613 } |
| 554 | 614 |
| 555 void PageLoadTracker::NotifyClientRedirectTo( | 615 void PageLoadTracker::NotifyClientRedirectTo( |
| 556 const PageLoadTracker& destination) { | 616 const PageLoadTracker& destination) { |
| 557 if (timing_.paint_timing.first_paint) { | 617 if (merged_page_timing_.paint_timing.first_paint) { |
| 558 base::TimeTicks first_paint_time = | 618 base::TimeTicks first_paint_time = |
| 559 navigation_start() + timing_.paint_timing.first_paint.value(); | 619 navigation_start() + |
| 620 merged_page_timing_.paint_timing.first_paint.value(); |
| 560 base::TimeDelta first_paint_to_navigation; | 621 base::TimeDelta first_paint_to_navigation; |
| 561 if (destination.navigation_start() > first_paint_time) | 622 if (destination.navigation_start() > first_paint_time) |
| 562 first_paint_to_navigation = | 623 first_paint_to_navigation = |
| 563 destination.navigation_start() - first_paint_time; | 624 destination.navigation_start() - first_paint_time; |
| 564 PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation, | 625 PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation, |
| 565 first_paint_to_navigation); | 626 first_paint_to_navigation); |
| 566 } else { | 627 } else { |
| 567 UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true); | 628 UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true); |
| 568 } | 629 } |
| 569 } | 630 } |
| 570 | 631 |
| 571 void PageLoadTracker::UpdateChildFrameMetadata( | 632 void PageLoadTracker::UpdateSubFrameTiming( |
| 572 const PageLoadMetadata& child_metadata) { | 633 content::RenderFrameHost* render_frame_host, |
| 573 // Merge the child loading behavior flags with any we've already observed, | 634 const PageLoadTiming& new_timing, |
| 574 // possibly from other child frames. | 635 const PageLoadMetadata& new_metadata) { |
| 575 const int last_child_loading_behavior_flags = | 636 UpdateSubFrameMetadata(new_metadata); |
| 576 child_frame_metadata_.behavior_flags; | 637 const auto it = subframe_navigation_start_offset_.find( |
| 577 child_frame_metadata_.behavior_flags |= child_metadata.behavior_flags; | 638 render_frame_host->GetFrameTreeNodeId()); |
| 578 if (last_child_loading_behavior_flags == child_frame_metadata_.behavior_flags) | 639 if (it == subframe_navigation_start_offset_.end()) { |
| 640 // We received timing information for an untracked load. Ignore it. |
| 641 return; |
| 642 } |
| 643 |
| 644 base::TimeDelta navigation_start_offset = it->second; |
| 645 const PageLoadTiming last_timing = merged_page_timing_; |
| 646 MergePaintTiming(navigation_start_offset, new_timing.paint_timing, |
| 647 false /* is_main_frame */); |
| 648 |
| 649 if (last_timing == merged_page_timing_) |
| 650 return; |
| 651 |
| 652 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 653 for (const auto& observer : observers_) { |
| 654 DispatchObserverTimingCallbacks(observer.get(), last_timing, |
| 655 merged_page_timing_, main_frame_metadata_, |
| 656 info); |
| 657 } |
| 658 } |
| 659 |
| 660 void PageLoadTracker::MergePaintTiming( |
| 661 base::TimeDelta navigation_start_offset, |
| 662 const page_load_metrics::PaintTiming& new_paint_timing, |
| 663 bool is_main_frame) { |
| 664 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_paint, |
| 665 navigation_start_offset, new_paint_timing.first_paint); |
| 666 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_text_paint, |
| 667 navigation_start_offset, |
| 668 new_paint_timing.first_text_paint); |
| 669 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_image_paint, |
| 670 navigation_start_offset, |
| 671 new_paint_timing.first_image_paint); |
| 672 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_contentful_paint, |
| 673 navigation_start_offset, |
| 674 new_paint_timing.first_contentful_paint); |
| 675 if (is_main_frame) { |
| 676 // first meaningful paint is only tracked in the main frame. |
| 677 merged_page_timing_.paint_timing.first_meaningful_paint = |
| 678 new_paint_timing.first_meaningful_paint; |
| 679 } |
| 680 } |
| 681 |
| 682 void PageLoadTracker::UpdateSubFrameMetadata( |
| 683 const PageLoadMetadata& subframe_metadata) { |
| 684 // Merge the subframe loading behavior flags with any we've already observed, |
| 685 // possibly from other subframes. |
| 686 const int last_subframe_loading_behavior_flags = |
| 687 subframe_metadata_.behavior_flags; |
| 688 subframe_metadata_.behavior_flags |= subframe_metadata.behavior_flags; |
| 689 if (last_subframe_loading_behavior_flags == subframe_metadata_.behavior_flags) |
| 579 return; | 690 return; |
| 580 | 691 |
| 581 PageLoadExtraInfo extra_info(ComputePageLoadExtraInfo()); | 692 PageLoadExtraInfo extra_info(ComputePageLoadExtraInfo()); |
| 582 for (const auto& observer : observers_) { | 693 for (const auto& observer : observers_) { |
| 583 observer->OnLoadingBehaviorObserved(extra_info); | 694 observer->OnLoadingBehaviorObserved(extra_info); |
| 584 } | 695 } |
| 585 } | 696 } |
| 586 | 697 |
| 587 void PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, | 698 void PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, |
| 588 const PageLoadMetadata& new_metadata) { | 699 const PageLoadMetadata& new_metadata) { |
| 589 // Throw away IPCs that are not relevant to the current navigation. | 700 // Throw away IPCs that are not relevant to the current navigation. |
| 590 // Two timing structures cannot refer to the same navigation if they indicate | 701 // Two timing structures cannot refer to the same navigation if they indicate |
| 591 // that a navigation started at different times, so a new timing struct with a | 702 // that a navigation started at different times, so a new timing struct with a |
| 592 // different start time from an earlier struct is considered invalid. | 703 // different start time from an earlier struct is considered invalid. |
| 593 const bool valid_timing_descendent = | 704 const bool valid_timing_descendent = |
| 594 timing_.navigation_start.is_null() || | 705 merged_page_timing_.navigation_start.is_null() || |
| 595 timing_.navigation_start == new_timing.navigation_start; | 706 merged_page_timing_.navigation_start == new_timing.navigation_start; |
| 596 if (!valid_timing_descendent) { | 707 if (!valid_timing_descendent) { |
| 597 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING_DESCENDENT); | 708 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING_DESCENDENT); |
| 598 return; | 709 return; |
| 599 } | 710 } |
| 600 | 711 |
| 601 // Ensure flags sent previously are still present in the new metadata fields. | 712 // Ensure flags sent previously are still present in the new metadata fields. |
| 602 const bool valid_behavior_descendent = | 713 const bool valid_behavior_descendent = |
| 603 (main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) == | 714 (main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) == |
| 604 main_frame_metadata_.behavior_flags; | 715 main_frame_metadata_.behavior_flags; |
| 605 if (!valid_behavior_descendent) { | 716 if (!valid_behavior_descendent) { |
| 606 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); | 717 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); |
| 607 return; | 718 return; |
| 608 } | 719 } |
| 609 internal::PageLoadTimingStatus status = IsValidPageLoadTiming(new_timing); | 720 internal::PageLoadTimingStatus status = IsValidPageLoadTiming(new_timing); |
| 610 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status, | 721 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status, |
| 611 internal::LAST_PAGE_LOAD_TIMING_STATUS); | 722 internal::LAST_PAGE_LOAD_TIMING_STATUS); |
| 612 if (status != internal::VALID) { | 723 if (status != internal::VALID) { |
| 613 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); | 724 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); |
| 614 return; | 725 return; |
| 615 } | 726 } |
| 616 | 727 |
| 617 DCHECK(did_commit_); // OnCommit() must be called first. | 728 DCHECK(did_commit_); // OnCommit() must be called first. |
| 618 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() | 729 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() |
| 619 // must be called before DispatchObserverTimingCallbacks, but its | 730 // must be called before DispatchObserverTimingCallbacks, but its |
| 620 // implementation depends on the state of main_frame_metadata_, so we need | 731 // implementation depends on the state of main_frame_metadata_, so we need |
| 621 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo. | 732 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo. |
| 622 // Thus, we make a copy of timing here, update timing_ and | 733 // Thus, we make a copy of timing here, update timing_ and |
| 623 // main_frame_metadata_, and then proceed to dispatch the observer timing | 734 // main_frame_metadata_, and then proceed to dispatch the observer timing |
| 624 // callbacks. | 735 // callbacks. |
| 625 const PageLoadTiming last_timing = timing_; | 736 const PageLoadTiming last_timing = merged_page_timing_; |
| 626 timing_ = new_timing; | 737 |
| 738 // Update the merged_page_timing_, making sure to merge the previously |
| 739 // observed |paint_timing|, which is tracked across all frames in the page. |
| 740 merged_page_timing_ = new_timing; |
| 741 merged_page_timing_.paint_timing = last_timing.paint_timing; |
| 742 MergePaintTiming(base::TimeDelta(), new_timing.paint_timing, |
| 743 true /* is_main_frame */); |
| 627 | 744 |
| 628 const PageLoadMetadata last_metadata = main_frame_metadata_; | 745 const PageLoadMetadata last_metadata = main_frame_metadata_; |
| 629 main_frame_metadata_ = new_metadata; | 746 main_frame_metadata_ = new_metadata; |
| 630 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 747 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
| 631 for (const auto& observer : observers_) { | 748 for (const auto& observer : observers_) { |
| 632 DispatchObserverTimingCallbacks(observer.get(), last_timing, new_timing, | 749 DispatchObserverTimingCallbacks(observer.get(), last_timing, |
| 633 last_metadata, info); | 750 merged_page_timing_, last_metadata, info); |
| 634 } | 751 } |
| 635 } | 752 } |
| 636 | 753 |
| 637 void PageLoadTracker::OnStartedResource( | 754 void PageLoadTracker::OnStartedResource( |
| 638 const ExtraRequestStartInfo& extra_request_start_info) { | 755 const ExtraRequestStartInfo& extra_request_start_info) { |
| 639 for (const auto& observer : observers_) { | 756 for (const auto& observer : observers_) { |
| 640 observer->OnStartedResource(extra_request_start_info); | 757 observer->OnStartedResource(extra_request_start_info); |
| 641 } | 758 } |
| 642 } | 759 } |
| 643 | 760 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 // page_end_reason_ == END_NONE implies page_end_user_initiated_info_ is not | 827 // page_end_reason_ == END_NONE implies page_end_user_initiated_info_ is not |
| 711 // user initiated. | 828 // user initiated. |
| 712 DCHECK(page_end_reason_ != END_NONE || | 829 DCHECK(page_end_reason_ != END_NONE || |
| 713 (!page_end_user_initiated_info_.browser_initiated && | 830 (!page_end_user_initiated_info_.browser_initiated && |
| 714 !page_end_user_initiated_info_.user_gesture && | 831 !page_end_user_initiated_info_.user_gesture && |
| 715 !page_end_user_initiated_info_.user_input_event)); | 832 !page_end_user_initiated_info_.user_input_event)); |
| 716 return PageLoadExtraInfo( | 833 return PageLoadExtraInfo( |
| 717 navigation_start_, first_background_time, first_foreground_time, | 834 navigation_start_, first_background_time, first_foreground_time, |
| 718 started_in_foreground_, user_initiated_info_, url(), start_url_, | 835 started_in_foreground_, user_initiated_info_, url(), start_url_, |
| 719 did_commit_, page_end_reason_, page_end_user_initiated_info_, | 836 did_commit_, page_end_reason_, page_end_user_initiated_info_, |
| 720 page_end_time, main_frame_metadata_, child_frame_metadata_); | 837 page_end_time, main_frame_metadata_, subframe_metadata_); |
| 721 } | 838 } |
| 722 | 839 |
| 723 bool PageLoadTracker::HasMatchingNavigationRequestID( | 840 bool PageLoadTracker::HasMatchingNavigationRequestID( |
| 724 const content::GlobalRequestID& request_id) const { | 841 const content::GlobalRequestID& request_id) const { |
| 725 DCHECK(request_id != content::GlobalRequestID()); | 842 DCHECK(request_id != content::GlobalRequestID()); |
| 726 return navigation_request_id_.has_value() && | 843 return navigation_request_id_.has_value() && |
| 727 navigation_request_id_.value() == request_id; | 844 navigation_request_id_.value() == request_id; |
| 728 } | 845 } |
| 729 | 846 |
| 730 void PageLoadTracker::NotifyPageEnd(PageEndReason page_end_reason, | 847 void PageLoadTracker::NotifyPageEnd(PageEndReason page_end_reason, |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 819 observer->MediaStartedPlaying(video_type, is_in_main_frame); | 936 observer->MediaStartedPlaying(video_type, is_in_main_frame); |
| 820 } | 937 } |
| 821 | 938 |
| 822 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay, | 939 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay, |
| 823 base::TimeDelta actual_delay) { | 940 base::TimeDelta actual_delay) { |
| 824 for (const auto& observer : observers_) | 941 for (const auto& observer : observers_) |
| 825 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay); | 942 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay); |
| 826 } | 943 } |
| 827 | 944 |
| 828 } // namespace page_load_metrics | 945 } // namespace page_load_metrics |
| OLD | NEW |