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

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

Issue 2859393002: Report page load timing information for child frames. (Closed)
Patch Set: rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/page_load_metrics/page_load_tracker.h" 5 #include "chrome/browser/page_load_metrics/page_load_tracker.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <ostream> 8 #include <ostream>
9 #include <string> 9 #include <string>
10 #include <utility> 10 #include <utility>
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/page_load_metrics/page_load_tracker.h ('k') | chrome/browser/prerender/prerender_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698