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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
98 // HasUserGesture() set to true. In the meantime, we consider all | 100 // HasUserGesture() set to true. In the meantime, we consider all |
99 // browser-initiated navigations to be user initiated. | 101 // browser-initiated navigations to be user initiated. |
100 // | 102 // |
101 // TODO(crbug.com/637345): Some browser-initiated navigations incorrectly | 103 // TODO(crbug.com/637345): Some browser-initiated navigations incorrectly |
102 // report that they are renderer-initiated. We will currently report that | 104 // report that they are renderer-initiated. We will currently report that |
103 // these navigations are not user initiated, when in fact they are user | 105 // these navigations are not user initiated, when in fact they are user |
104 // initiated. | 106 // initiated. |
105 return handle->HasUserGesture() || !handle->IsRendererInitiated(); | 107 return handle->HasUserGesture() || !handle->IsRendererInitiated(); |
106 } | 108 } |
107 | 109 |
110 content::RenderFrameHost* GetMainFrame(content::RenderFrameHost* rfh) { | |
111 // Don't use rfh->GetRenderViewHost()->GetMainFrame() here because | |
112 // RenderViewHost is being deprecated and because in OOPIF, | |
113 // RenderViewHost::GetMainFrame() returns nullptr for child frames hosted in a | |
114 // different process from the main frame. | |
115 while (rfh->GetParent() != nullptr) | |
116 rfh = rfh->GetParent(); | |
117 return rfh; | |
118 } | |
119 | |
108 namespace { | 120 namespace { |
109 | 121 |
110 // Helper to allow use of Optional<> values in LOG() messages. | 122 // Helper to allow use of Optional<> values in LOG() messages. |
111 std::ostream& operator<<(std::ostream& os, | 123 std::ostream& operator<<(std::ostream& os, |
112 const base::Optional<base::TimeDelta>& opt) { | 124 const base::Optional<base::TimeDelta>& opt) { |
113 if (opt) | 125 if (opt) |
114 os << opt.value(); | 126 os << opt.value(); |
115 else | 127 else |
116 os << "(unset)"; | 128 os << "(unset)"; |
117 return os; | 129 return os; |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 timing.paint_timing.first_meaningful_paint)) { | 275 timing.paint_timing.first_meaningful_paint)) { |
264 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint | 276 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint |
265 << " for first_meaningful_paint " | 277 << " for first_meaningful_paint " |
266 << timing.paint_timing.first_meaningful_paint; | 278 << timing.paint_timing.first_meaningful_paint; |
267 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; | 279 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; |
268 } | 280 } |
269 | 281 |
270 return internal::VALID; | 282 return internal::VALID; |
271 } | 283 } |
272 | 284 |
285 // Updates *|inout_existing_value| with |optional_candidate_new_value|, if | |
286 // either *|inout_existing_value| isn't set, or |optional_candidate_new_value| < | |
287 // |inout_existing_value|. | |
288 void MaybeUpdateTimeDelta( | |
289 base::Optional<base::TimeDelta>* inout_existing_value, | |
290 base::TimeDelta navigation_start_offset, | |
291 const base::Optional<base::TimeDelta>& optional_candidate_new_value) { | |
292 // If we don't get a new value, there's nothing to do | |
293 if (!optional_candidate_new_value) | |
294 return; | |
295 | |
296 // optional_candidate_new_value is relative to navigation start in its | |
297 // frame. We need to adjust it to be relative to navigation start in the main | |
298 // frame, so offset it by navigation_start_offset. | |
299 base::TimeDelta candidate_new_value = | |
300 navigation_start_offset + optional_candidate_new_value.value(); | |
301 | |
302 if (*inout_existing_value) { | |
303 // If we have a new value, but it is after the existing value, then keep the | |
304 // existing value. | |
305 if (*inout_existing_value <= candidate_new_value) | |
306 return; | |
307 | |
308 // We received a new timing event, but with a timestamp before the timestamp | |
309 // of a timing update we had received previously. We expect this to happen | |
310 // occasionally, as inter-frame updates can arrive out of order. Record a | |
311 // histogram to track how frequently it happens, along with the magnitude | |
312 // of the delta. | |
313 PAGE_LOAD_HISTOGRAM("PageLoad.Internal.OutOfOrderInterFrameTiming", | |
314 inout_existing_value->value() - candidate_new_value); | |
315 } | |
316 | |
317 *inout_existing_value = candidate_new_value; | |
318 } | |
319 | |
273 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { | 320 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { |
274 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, | 321 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, |
275 completed_after_background); | 322 completed_after_background); |
276 } | 323 } |
277 | 324 |
278 void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer, | 325 void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer, |
279 const PageLoadTiming& last_timing, | 326 const PageLoadTiming& last_timing, |
280 const PageLoadTiming& new_timing, | 327 const PageLoadTiming& new_timing, |
281 const PageLoadMetadata& last_metadata, | 328 const PageLoadMetadata& last_metadata, |
282 const PageLoadExtraInfo& extra_info) { | 329 const PageLoadExtraInfo& extra_info) { |
283 if (extra_info.main_frame_metadata.behavior_flags != | 330 if (extra_info.main_frame_metadata.behavior_flags != |
284 last_metadata.behavior_flags) | 331 last_metadata.behavior_flags) |
285 observer->OnLoadingBehaviorObserved(extra_info); | 332 observer->OnLoadingBehaviorObserved(extra_info); |
286 if (last_timing != new_timing) | 333 if (last_timing != new_timing) |
287 observer->OnTimingUpdate(new_timing, extra_info); | 334 observer->OnTimingUpdate(new_timing, extra_info); |
288 if (new_timing.document_timing.dom_content_loaded_event_start && | 335 if (new_timing.document_timing.dom_content_loaded_event_start && |
289 !last_timing.document_timing.dom_content_loaded_event_start) | 336 !last_timing.document_timing.dom_content_loaded_event_start) |
290 observer->OnDomContentLoadedEventStart(new_timing, extra_info); | 337 observer->OnDomContentLoadedEventStart(new_timing, extra_info); |
291 if (new_timing.document_timing.load_event_start && | 338 if (new_timing.document_timing.load_event_start && |
292 !last_timing.document_timing.load_event_start) | 339 !last_timing.document_timing.load_event_start) |
293 observer->OnLoadEventStart(new_timing, extra_info); | 340 observer->OnLoadEventStart(new_timing, extra_info); |
294 if (new_timing.document_timing.first_layout && | 341 if (new_timing.document_timing.first_layout && |
295 !last_timing.document_timing.first_layout) | 342 !last_timing.document_timing.first_layout) |
296 observer->OnFirstLayout(new_timing, extra_info); | 343 observer->OnFirstLayout(new_timing, extra_info); |
297 if (new_timing.paint_timing.first_paint && | 344 if (new_timing.paint_timing.first_paint && |
298 !last_timing.paint_timing.first_paint) | 345 !last_timing.paint_timing.first_paint) |
299 observer->OnFirstPaint(new_timing, extra_info); | 346 observer->OnFirstPaintInPage(new_timing, extra_info); |
300 if (new_timing.paint_timing.first_text_paint && | 347 if (new_timing.paint_timing.first_text_paint && |
301 !last_timing.paint_timing.first_text_paint) | 348 !last_timing.paint_timing.first_text_paint) |
302 observer->OnFirstTextPaint(new_timing, extra_info); | 349 observer->OnFirstTextPaintInPage(new_timing, extra_info); |
303 if (new_timing.paint_timing.first_image_paint && | 350 if (new_timing.paint_timing.first_image_paint && |
304 !last_timing.paint_timing.first_image_paint) | 351 !last_timing.paint_timing.first_image_paint) |
305 observer->OnFirstImagePaint(new_timing, extra_info); | 352 observer->OnFirstImagePaintInPage(new_timing, extra_info); |
306 if (new_timing.paint_timing.first_contentful_paint && | 353 if (new_timing.paint_timing.first_contentful_paint && |
307 !last_timing.paint_timing.first_contentful_paint) | 354 !last_timing.paint_timing.first_contentful_paint) |
308 observer->OnFirstContentfulPaint(new_timing, extra_info); | 355 observer->OnFirstContentfulPaintInPage(new_timing, extra_info); |
309 if (new_timing.paint_timing.first_meaningful_paint && | 356 if (new_timing.paint_timing.first_meaningful_paint && |
310 !last_timing.paint_timing.first_meaningful_paint) | 357 !last_timing.paint_timing.first_meaningful_paint) |
311 observer->OnFirstMeaningfulPaint(new_timing, extra_info); | 358 observer->OnFirstMeaningfulPaintInMainFrameDocument(new_timing, extra_info); |
312 if (new_timing.parse_timing.parse_start && | 359 if (new_timing.parse_timing.parse_start && |
313 !last_timing.parse_timing.parse_start) | 360 !last_timing.parse_timing.parse_start) |
314 observer->OnParseStart(new_timing, extra_info); | 361 observer->OnParseStart(new_timing, extra_info); |
315 if (new_timing.parse_timing.parse_stop && | 362 if (new_timing.parse_timing.parse_stop && |
316 !last_timing.parse_timing.parse_stop) | 363 !last_timing.parse_timing.parse_stop) |
317 observer->OnParseStop(new_timing, extra_info); | 364 observer->OnParseStop(new_timing, extra_info); |
318 } | 365 } |
319 | 366 |
320 } // namespace | 367 } // namespace |
321 | 368 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
376 if (!failed_provisional_load_info_) | 423 if (!failed_provisional_load_info_) |
377 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); | 424 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); |
378 | 425 |
379 // Don't include any aborts that resulted in a new navigation, as the chain | 426 // Don't include any aborts that resulted in a new navigation, as the chain |
380 // length will be included in the aborter PageLoadTracker. | 427 // length will be included in the aborter PageLoadTracker. |
381 if (page_end_reason_ != END_RELOAD && | 428 if (page_end_reason_ != END_RELOAD && |
382 page_end_reason_ != END_FORWARD_BACK && | 429 page_end_reason_ != END_FORWARD_BACK && |
383 page_end_reason_ != END_NEW_NAVIGATION) { | 430 page_end_reason_ != END_NEW_NAVIGATION) { |
384 LogAbortChainHistograms(nullptr); | 431 LogAbortChainHistograms(nullptr); |
385 } | 432 } |
386 } else if (timing_.IsEmpty()) { | 433 } else if (merged_page_timing_.IsEmpty()) { |
387 RecordInternalError(ERR_NO_IPCS_RECEIVED); | 434 RecordInternalError(ERR_NO_IPCS_RECEIVED); |
388 } | 435 } |
389 | 436 |
390 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 437 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
391 for (const auto& observer : observers_) { | 438 for (const auto& observer : observers_) { |
392 if (failed_provisional_load_info_) { | 439 if (failed_provisional_load_info_) { |
393 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); | 440 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); |
394 } else if (did_commit_) { | 441 } else if (did_commit_) { |
395 observer->OnComplete(timing_, info); | 442 observer->OnComplete(merged_page_timing_, info); |
396 } | 443 } |
397 } | 444 } |
398 } | 445 } |
399 | 446 |
400 void PageLoadTracker::LogAbortChainHistograms( | 447 void PageLoadTracker::LogAbortChainHistograms( |
401 content::NavigationHandle* final_navigation) { | 448 content::NavigationHandle* final_navigation) { |
402 if (aborted_chain_size_ == 0) | 449 if (aborted_chain_size_ == 0) |
403 return; | 450 return; |
404 // Note that this could be broken out by this navigation's abort type, if more | 451 // Note that this could be broken out by this navigation's abort type, if more |
405 // granularity is needed. Add one to the chain size to count the current | 452 // 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... | |
452 // Only log the first time we background in a given page load. | 499 // Only log the first time we background in a given page load. |
453 if (background_time_.is_null()) { | 500 if (background_time_.is_null()) { |
454 // Make sure we either started in the foreground and haven't been | 501 // Make sure we either started in the foreground and haven't been |
455 // foregrounded yet, or started in the background and have already been | 502 // foregrounded yet, or started in the background and have already been |
456 // foregrounded. | 503 // foregrounded. |
457 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); | 504 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); |
458 background_time_ = base::TimeTicks::Now(); | 505 background_time_ = base::TimeTicks::Now(); |
459 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); | 506 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); |
460 } | 507 } |
461 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 508 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
462 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, timing_, info); | 509 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, merged_page_timing_, info); |
463 } | 510 } |
464 | 511 |
465 void PageLoadTracker::WebContentsShown() { | 512 void PageLoadTracker::WebContentsShown() { |
466 // Only log the first time we foreground in a given page load. | 513 // Only log the first time we foreground in a given page load. |
467 if (foreground_time_.is_null()) { | 514 if (foreground_time_.is_null()) { |
468 // Make sure we either started in the background and haven't been | 515 // Make sure we either started in the background and haven't been |
469 // backgrounded yet, or started in the foreground and have already been | 516 // backgrounded yet, or started in the foreground and have already been |
470 // backgrounded. | 517 // backgrounded. |
471 DCHECK_NE(started_in_foreground_, background_time_.is_null()); | 518 DCHECK_NE(started_in_foreground_, background_time_.is_null()); |
472 foreground_time_ = base::TimeTicks::Now(); | 519 foreground_time_ = base::TimeTicks::Now(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
504 navigation_handle->GetWebContents()->GetContentsMimeType()); | 551 navigation_handle->GetWebContents()->GetContentsMimeType()); |
505 | 552 |
506 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnCommit, navigation_handle); | 553 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnCommit, navigation_handle); |
507 LogAbortChainHistograms(navigation_handle); | 554 LogAbortChainHistograms(navigation_handle); |
508 } | 555 } |
509 | 556 |
510 void PageLoadTracker::DidFinishSubFrameNavigation( | 557 void PageLoadTracker::DidFinishSubFrameNavigation( |
511 content::NavigationHandle* navigation_handle) { | 558 content::NavigationHandle* navigation_handle) { |
512 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnDidFinishSubFrameNavigation, | 559 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnDidFinishSubFrameNavigation, |
513 navigation_handle); | 560 navigation_handle); |
561 | |
562 if (!navigation_handle->HasCommitted()) | |
563 return; | |
564 | |
565 // We have a new committed navigation, so discard information about the | |
566 // previously committed navigation. | |
567 child_frame_navigation_start_offset_.erase( | |
568 navigation_handle->GetFrameTreeNodeId()); | |
569 | |
570 if (GetMainFrame(navigation_handle->GetRenderFrameHost()) != | |
571 navigation_handle->GetWebContents()->GetMainFrame()) { | |
572 // Ignore navigations for a main frame that was navigated away from. | |
573 return; | |
574 } | |
575 | |
576 BrowserPageTrackDecider decider(embedder_interface_, | |
577 navigation_handle->GetWebContents(), | |
578 navigation_handle); | |
579 if (!decider.ShouldTrack()) | |
580 return; | |
581 | |
582 if (navigation_start_ > navigation_handle->NavigationStart()) { | |
583 RecordInternalError(ERR_SUBFRAME_NAVIGATION_START_BEFORE_MAIN_FRAME); | |
584 return; | |
585 } | |
586 base::TimeDelta navigation_delta = | |
587 navigation_handle->NavigationStart() - navigation_start_; | |
588 child_frame_navigation_start_offset_.insert(std::make_pair( | |
589 navigation_handle->GetFrameTreeNodeId(), navigation_delta)); | |
514 } | 590 } |
515 | 591 |
516 void PageLoadTracker::FailedProvisionalLoad( | 592 void PageLoadTracker::FailedProvisionalLoad( |
517 content::NavigationHandle* navigation_handle, | 593 content::NavigationHandle* navigation_handle, |
518 base::TimeTicks failed_load_time) { | 594 base::TimeTicks failed_load_time) { |
519 DCHECK(!failed_provisional_load_info_); | 595 DCHECK(!failed_provisional_load_info_); |
520 failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo( | 596 failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo( |
521 failed_load_time - navigation_handle->NavigationStart(), | 597 failed_load_time - navigation_handle->NavigationStart(), |
522 navigation_handle->GetNetErrorCode())); | 598 navigation_handle->GetNetErrorCode())); |
523 } | 599 } |
(...skipping 11 matching lines...) Expand all Loading... | |
535 } | 611 } |
536 | 612 |
537 void PageLoadTracker::FlushMetricsOnAppEnterBackground() { | 613 void PageLoadTracker::FlushMetricsOnAppEnterBackground() { |
538 if (!app_entered_background_) { | 614 if (!app_entered_background_) { |
539 RecordAppBackgroundPageLoadCompleted(false); | 615 RecordAppBackgroundPageLoadCompleted(false); |
540 app_entered_background_ = true; | 616 app_entered_background_ = true; |
541 } | 617 } |
542 | 618 |
543 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 619 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
544 INVOKE_AND_PRUNE_OBSERVERS(observers_, FlushMetricsOnAppEnterBackground, | 620 INVOKE_AND_PRUNE_OBSERVERS(observers_, FlushMetricsOnAppEnterBackground, |
545 timing_, info); | 621 merged_page_timing_, info); |
546 } | 622 } |
547 | 623 |
548 void PageLoadTracker::NotifyClientRedirectTo( | 624 void PageLoadTracker::NotifyClientRedirectTo( |
549 const PageLoadTracker& destination) { | 625 const PageLoadTracker& destination) { |
550 if (timing_.paint_timing.first_paint) { | 626 if (merged_page_timing_.paint_timing.first_paint) { |
551 base::TimeTicks first_paint_time = | 627 base::TimeTicks first_paint_time = |
552 navigation_start() + timing_.paint_timing.first_paint.value(); | 628 navigation_start() + |
629 merged_page_timing_.paint_timing.first_paint.value(); | |
553 base::TimeDelta first_paint_to_navigation; | 630 base::TimeDelta first_paint_to_navigation; |
554 if (destination.navigation_start() > first_paint_time) | 631 if (destination.navigation_start() > first_paint_time) |
555 first_paint_to_navigation = | 632 first_paint_to_navigation = |
556 destination.navigation_start() - first_paint_time; | 633 destination.navigation_start() - first_paint_time; |
557 PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation, | 634 PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation, |
558 first_paint_to_navigation); | 635 first_paint_to_navigation); |
559 } else { | 636 } else { |
560 UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true); | 637 UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true); |
561 } | 638 } |
562 } | 639 } |
563 | 640 |
564 void PageLoadTracker::UpdateChildFrameMetadata( | 641 void PageLoadTracker::UpdateSubFrameTiming( |
642 content::RenderFrameHost* render_frame_host, | |
643 const PageLoadTiming& new_timing, | |
644 const PageLoadMetadata& new_metadata) { | |
645 UpdateSubFrameMetadata(new_metadata); | |
646 const auto it = child_frame_navigation_start_offset_.find( | |
647 render_frame_host->GetFrameTreeNodeId()); | |
648 if (it == child_frame_navigation_start_offset_.end()) { | |
649 // We received timing information for an untracked load. Ignore it. | |
650 RecordInternalError(ERR_SUBFRAME_IPC_WITH_NO_RELEVANT_LOAD); | |
651 return; | |
652 } | |
653 | |
654 base::TimeDelta navigation_start_offset = it->second; | |
655 const PageLoadTiming last_timing = merged_page_timing_; | |
656 MergePaintTiming(navigation_start_offset, new_timing.paint_timing, | |
657 false /* is_main_frame */); | |
658 | |
659 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | |
660 for (const auto& observer : observers_) { | |
661 observer->OnSubFrameTimingUpdate(render_frame_host->GetFrameTreeNodeId(), | |
662 navigation_start_offset, new_timing, | |
663 new_metadata, info); | |
664 DispatchObserverTimingCallbacks(observer.get(), last_timing, | |
jkarlin
2017/05/10 16:55:28
It's potentially expensive to call all the observe
Bryan McQuade
2017/05/10 18:06:15
done
| |
665 merged_page_timing_, main_frame_metadata_, | |
666 info); | |
667 } | |
668 } | |
669 | |
670 void PageLoadTracker::MergePaintTiming( | |
671 base::TimeDelta navigation_start_offset, | |
672 const page_load_metrics::PaintTiming& new_paint_timing, | |
673 bool is_main_frame) { | |
674 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_paint, | |
675 navigation_start_offset, new_paint_timing.first_paint); | |
676 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_text_paint, | |
677 navigation_start_offset, | |
678 new_paint_timing.first_text_paint); | |
679 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_image_paint, | |
680 navigation_start_offset, | |
681 new_paint_timing.first_image_paint); | |
682 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_contentful_paint, | |
683 navigation_start_offset, | |
684 new_paint_timing.first_contentful_paint); | |
685 if (is_main_frame) { | |
686 // first meaningful paint is only tracked in the main frame. | |
687 merged_page_timing_.paint_timing.first_meaningful_paint = | |
688 new_paint_timing.first_meaningful_paint; | |
689 } | |
690 } | |
691 | |
692 void PageLoadTracker::UpdateSubFrameMetadata( | |
565 const PageLoadMetadata& child_metadata) { | 693 const PageLoadMetadata& child_metadata) { |
566 // Merge the child loading behavior flags with any we've already observed, | 694 // Merge the child loading behavior flags with any we've already observed, |
567 // possibly from other child frames. | 695 // possibly from other child frames. |
568 const int last_child_loading_behavior_flags = | 696 const int last_child_loading_behavior_flags = |
569 child_frame_metadata_.behavior_flags; | 697 child_frame_metadata_.behavior_flags; |
570 child_frame_metadata_.behavior_flags |= child_metadata.behavior_flags; | 698 child_frame_metadata_.behavior_flags |= child_metadata.behavior_flags; |
571 if (last_child_loading_behavior_flags == child_frame_metadata_.behavior_flags) | 699 if (last_child_loading_behavior_flags == child_frame_metadata_.behavior_flags) |
572 return; | 700 return; |
573 | 701 |
574 PageLoadExtraInfo extra_info(ComputePageLoadExtraInfo()); | 702 PageLoadExtraInfo extra_info(ComputePageLoadExtraInfo()); |
575 for (const auto& observer : observers_) { | 703 for (const auto& observer : observers_) { |
576 observer->OnLoadingBehaviorObserved(extra_info); | 704 observer->OnLoadingBehaviorObserved(extra_info); |
577 } | 705 } |
578 } | 706 } |
579 | 707 |
580 void PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, | 708 void PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, |
581 const PageLoadMetadata& new_metadata) { | 709 const PageLoadMetadata& new_metadata) { |
582 // Throw away IPCs that are not relevant to the current navigation. | 710 // Throw away IPCs that are not relevant to the current navigation. |
583 // Two timing structures cannot refer to the same navigation if they indicate | 711 // Two timing structures cannot refer to the same navigation if they indicate |
584 // that a navigation started at different times, so a new timing struct with a | 712 // that a navigation started at different times, so a new timing struct with a |
585 // different start time from an earlier struct is considered invalid. | 713 // different start time from an earlier struct is considered invalid. |
586 const bool valid_timing_descendent = | 714 const bool valid_timing_descendent = |
587 timing_.navigation_start.is_null() || | 715 merged_page_timing_.navigation_start.is_null() || |
588 timing_.navigation_start == new_timing.navigation_start; | 716 merged_page_timing_.navigation_start == new_timing.navigation_start; |
589 if (!valid_timing_descendent) { | 717 if (!valid_timing_descendent) { |
590 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING_DESCENDENT); | 718 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING_DESCENDENT); |
591 return; | 719 return; |
592 } | 720 } |
593 | 721 |
594 // Ensure flags sent previously are still present in the new metadata fields. | 722 // Ensure flags sent previously are still present in the new metadata fields. |
595 const bool valid_behavior_descendent = | 723 const bool valid_behavior_descendent = |
596 (main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) == | 724 (main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) == |
597 main_frame_metadata_.behavior_flags; | 725 main_frame_metadata_.behavior_flags; |
598 if (!valid_behavior_descendent) { | 726 if (!valid_behavior_descendent) { |
599 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); | 727 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); |
600 return; | 728 return; |
601 } | 729 } |
602 internal::PageLoadTimingStatus status = IsValidPageLoadTiming(new_timing); | 730 internal::PageLoadTimingStatus status = IsValidPageLoadTiming(new_timing); |
603 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status, | 731 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status, |
604 internal::LAST_PAGE_LOAD_TIMING_STATUS); | 732 internal::LAST_PAGE_LOAD_TIMING_STATUS); |
605 if (status != internal::VALID) { | 733 if (status != internal::VALID) { |
606 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); | 734 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); |
607 return; | 735 return; |
608 } | 736 } |
609 | 737 |
610 DCHECK(did_commit_); // OnCommit() must be called first. | 738 DCHECK(did_commit_); // OnCommit() must be called first. |
611 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() | 739 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() |
612 // must be called before DispatchObserverTimingCallbacks, but its | 740 // must be called before DispatchObserverTimingCallbacks, but its |
613 // implementation depends on the state of main_frame_metadata_, so we need | 741 // implementation depends on the state of main_frame_metadata_, so we need |
614 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo. | 742 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo. |
615 // Thus, we make a copy of timing here, update timing_ and | 743 // Thus, we make a copy of timing here, update timing_ and |
616 // main_frame_metadata_, and then proceed to dispatch the observer timing | 744 // main_frame_metadata_, and then proceed to dispatch the observer timing |
617 // callbacks. | 745 // callbacks. |
618 const PageLoadTiming last_timing = timing_; | 746 const PageLoadTiming last_timing = merged_page_timing_; |
619 timing_ = new_timing; | 747 |
748 // Update the merged_page_timing_, making sure to merge the previously | |
749 // observed |paint_timing|, which is tracked across all frames in the page. | |
750 merged_page_timing_ = new_timing; | |
751 merged_page_timing_.paint_timing = last_timing.paint_timing; | |
752 MergePaintTiming(base::TimeDelta(), new_timing.paint_timing, | |
753 true /* is_main_frame */); | |
620 | 754 |
621 const PageLoadMetadata last_metadata = main_frame_metadata_; | 755 const PageLoadMetadata last_metadata = main_frame_metadata_; |
622 main_frame_metadata_ = new_metadata; | 756 main_frame_metadata_ = new_metadata; |
623 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); | 757 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); |
624 for (const auto& observer : observers_) { | 758 for (const auto& observer : observers_) { |
625 DispatchObserverTimingCallbacks(observer.get(), last_timing, new_timing, | 759 DispatchObserverTimingCallbacks(observer.get(), last_timing, |
626 last_metadata, info); | 760 merged_page_timing_, last_metadata, info); |
627 } | 761 } |
628 } | 762 } |
629 | 763 |
630 void PageLoadTracker::OnStartedResource( | 764 void PageLoadTracker::OnStartedResource( |
631 const ExtraRequestStartInfo& extra_request_start_info) { | 765 const ExtraRequestStartInfo& extra_request_start_info) { |
632 for (const auto& observer : observers_) { | 766 for (const auto& observer : observers_) { |
633 observer->OnStartedResource(extra_request_start_info); | 767 observer->OnStartedResource(extra_request_start_info); |
634 } | 768 } |
635 } | 769 } |
636 | 770 |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
812 observer->MediaStartedPlaying(video_type, is_in_main_frame); | 946 observer->MediaStartedPlaying(video_type, is_in_main_frame); |
813 } | 947 } |
814 | 948 |
815 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay, | 949 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay, |
816 base::TimeDelta actual_delay) { | 950 base::TimeDelta actual_delay) { |
817 for (const auto& observer : observers_) | 951 for (const auto& observer : observers_) |
818 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay); | 952 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay); |
819 } | 953 } |
820 | 954 |
821 } // namespace page_load_metrics | 955 } // namespace page_load_metrics |
OLD | NEW |