Commit 2a2a964c authored by bmcquade's avatar bmcquade Committed by Commit bot

Add support for tracking loading behavior of child frames.

This is required for the existing subresource filtering and css scanning
page load metrics, as well as for the upcoming metrics for pages where
media is played.

In the render process:
* move policy decision about whether to process timing or metadata updates
  from blink to chrome/renderer/page_load_metrics code
* instantiate MetricsRenderFrameObservers for child frames
* track metadata updates for child frames
* send at most one update per second per frame over IPC to the browser process
  (this is the existing page load metrics IPC policy)

In the browser process:
* track child frame loading behavior flags
* notify observers whenever the loading behavior flags for a child frame
  are updated

In the SubresourceFilterMetricsObserver:
* consider the page to have filtered subresources if subresource filter loading
  behavior is observed in either the main frame or child frames

Note that we still do not track timing updates for child frames. This change
gets us closer to being able to do so, but given that there is no current
need, we don't do this for the time being.

BUG=699849

Review-Url: https://codereview.chromium.org/2737563007
Cr-Commit-Position: refs/heads/master@{#456166}
parent 0e08dc7a
......@@ -512,7 +512,9 @@ void MetricsWebContentsObserver::OnTimingUpdated(
const PageLoadMetadata& metadata) {
// We may receive notifications from frames that have been navigated away
// from. We simply ignore them.
if (render_frame_host != web_contents()->GetMainFrame()) {
if (!render_frame_host->GetRenderViewHost() ||
render_frame_host->GetRenderViewHost()->GetMainFrame() !=
web_contents()->GetMainFrame()) {
RecordInternalError(ERR_IPC_FROM_WRONG_FRAME);
return;
}
......@@ -535,6 +537,15 @@ void MetricsWebContentsObserver::OnTimingUpdated(
if (error)
return;
if (render_frame_host->GetParent() != nullptr) {
// Child frames may send PageLoadMetadata updates, but not PageLoadTiming
// updates.
if (!timing.IsEmpty())
RecordInternalError(ERR_TIMING_IPC_FROM_SUBFRAME);
committed_load_->UpdateChildFrameMetadata(metadata);
return;
}
if (!committed_load_->UpdateTiming(timing, metadata)) {
// If the page load tracker cannot update its timing, something is wrong
// with the IPC (it's from another load, or it's invalid in some other way).
......
......@@ -279,7 +279,7 @@ TEST_F(MetricsWebContentsObserverTest, NotInMainFrame) {
ASSERT_EQ(0, CountUpdatedTimingReported());
ASSERT_EQ(1, CountCompleteTimingReported());
ASSERT_EQ(1, CountEmptyCompleteTimingReported());
CheckErrorEvent(ERR_IPC_FROM_WRONG_FRAME, 1);
CheckErrorEvent(ERR_TIMING_IPC_FROM_SUBFRAME, 1);
CheckErrorEvent(ERR_NO_IPCS_RECEIVED, 1);
CheckTotalErrorEvents();
}
......@@ -368,7 +368,7 @@ TEST_F(MetricsWebContentsObserverTest, NotInMainError) {
subframe_tester->SimulateNavigationStart(GURL(kDefaultTestUrl2));
subframe_tester->SimulateNavigationCommit(GURL(kDefaultTestUrl2));
SimulateTimingUpdate(timing, subframe);
CheckErrorEvent(ERR_IPC_FROM_WRONG_FRAME, 1);
CheckErrorEvent(ERR_TIMING_IPC_FROM_SUBFRAME, 1);
CheckTotalErrorEvents();
ASSERT_EQ(0, CountUpdatedTimingReported());
ASSERT_EQ(0, CountCompleteTimingReported());
......
......@@ -11,30 +11,50 @@ CssScanningMetricsObserver::CssScanningMetricsObserver() {}
CssScanningMetricsObserver::~CssScanningMetricsObserver() {}
void CssScanningMetricsObserver::OnLoadingBehaviorObserved(
const page_load_metrics::PageLoadExtraInfo& info) {
if (css_preload_found_)
return;
css_preload_found_ = page_load_metrics::DidObserveLoadingBehaviorInAnyFrame(
info, blink::WebLoadingBehaviorFlag::WebLoadingBehaviorCSSPreloadFound);
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
CssScanningMetricsObserver::OnStart(
content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url,
bool started_in_foreground) {
return started_in_foreground ? CONTINUE_OBSERVING : STOP_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
CssScanningMetricsObserver::OnHidden(
const page_load_metrics::PageLoadTiming&,
const page_load_metrics::PageLoadExtraInfo&) {
return STOP_OBSERVING;
}
void CssScanningMetricsObserver::OnFirstContentfulPaint(
const page_load_metrics::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) {
if (info.metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::WebLoadingBehaviorCSSPreloadFound &&
WasStartedInForegroundOptionalEventInForeground(
timing.first_contentful_paint, info)) {
PAGE_LOAD_HISTOGRAM(
"PageLoad.Clients.CssScanner.PaintTiming."
"ParseStartToFirstContentfulPaint",
timing.first_contentful_paint.value() - timing.parse_start.value());
}
if (!css_preload_found_)
return;
PAGE_LOAD_HISTOGRAM(
"PageLoad.Clients.CssScanner.PaintTiming."
"ParseStartToFirstContentfulPaint",
timing.first_contentful_paint.value() - timing.parse_start.value());
}
void CssScanningMetricsObserver::OnFirstMeaningfulPaint(
const page_load_metrics::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) {
if (info.metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::WebLoadingBehaviorCSSPreloadFound &&
WasStartedInForegroundOptionalEventInForeground(
timing.first_meaningful_paint, info)) {
PAGE_LOAD_HISTOGRAM(
"PageLoad.Clients.CssScanner.Experimental.PaintTiming."
"ParseStartToFirstMeaningfulPaint",
timing.first_meaningful_paint.value() - timing.parse_start.value());
}
if (!css_preload_found_)
return;
PAGE_LOAD_HISTOGRAM(
"PageLoad.Clients.CssScanner.Experimental.PaintTiming."
"ParseStartToFirstMeaningfulPaint",
timing.first_meaningful_paint.value() - timing.parse_start.value());
}
......@@ -15,6 +15,14 @@ class CssScanningMetricsObserver
~CssScanningMetricsObserver() override;
// page_load_metrics::PageLoadMetricsObserver:
ObservePolicy OnStart(content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url,
bool started_in_foreground) override;
ObservePolicy OnHidden(
const page_load_metrics::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) override;
void OnLoadingBehaviorObserved(
const page_load_metrics::PageLoadExtraInfo& info) override;
void OnFirstContentfulPaint(
const page_load_metrics::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) override;
......@@ -23,6 +31,8 @@ class CssScanningMetricsObserver
const page_load_metrics::PageLoadExtraInfo& info) override;
private:
bool css_preload_found_ = false;
DISALLOW_COPY_AND_ASSIGN(CssScanningMetricsObserver);
};
......
......@@ -79,11 +79,11 @@ const char kHistogramDocWriteBlockLoadingBehavior[] =
void DocumentWritePageLoadMetricsObserver::OnFirstContentfulPaint(
const page_load_metrics::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) {
if (info.metadata.behavior_flags &
if (info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::WebLoadingBehaviorDocumentWriteEvaluator) {
LogDocumentWriteEvaluatorFirstContentfulPaint(timing, info);
}
if (info.metadata.behavior_flags &
if (info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::WebLoadingBehaviorDocumentWriteBlock) {
LogDocumentWriteBlockFirstContentfulPaint(timing, info);
}
......@@ -92,11 +92,11 @@ void DocumentWritePageLoadMetricsObserver::OnFirstContentfulPaint(
void DocumentWritePageLoadMetricsObserver::OnFirstMeaningfulPaint(
const page_load_metrics::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) {
if (info.metadata.behavior_flags &
if (info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::WebLoadingBehaviorDocumentWriteEvaluator) {
LogDocumentWriteEvaluatorFirstMeaningfulPaint(timing, info);
}
if (info.metadata.behavior_flags &
if (info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::WebLoadingBehaviorDocumentWriteBlock) {
LogDocumentWriteBlockFirstMeaningfulPaint(timing, info);
}
......@@ -105,11 +105,11 @@ void DocumentWritePageLoadMetricsObserver::OnFirstMeaningfulPaint(
void DocumentWritePageLoadMetricsObserver::OnParseStop(
const page_load_metrics::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) {
if (info.metadata.behavior_flags &
if (info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::WebLoadingBehaviorDocumentWriteEvaluator) {
LogDocumentWriteEvaluatorParseStop(timing, info);
}
if (info.metadata.behavior_flags &
if (info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::WebLoadingBehaviorDocumentWriteBlock) {
LogDocumentWriteBlockParseStop(timing, info);
}
......@@ -124,25 +124,25 @@ void LogLoadingBehaviorMetrics(
void DocumentWritePageLoadMetricsObserver::OnLoadingBehaviorObserved(
const page_load_metrics::PageLoadExtraInfo& info) {
if ((info.metadata.behavior_flags &
if ((info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::
WebLoadingBehaviorDocumentWriteBlockReload) &&
!doc_write_block_reload_observed_) {
DCHECK(
!(info.metadata.behavior_flags &
!(info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::WebLoadingBehaviorDocumentWriteBlock));
UMA_HISTOGRAM_COUNTS(internal::kHistogramDocWriteBlockReloadCount, 1);
LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_RELOAD);
doc_write_block_reload_observed_ = true;
}
if ((info.metadata.behavior_flags &
if ((info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::WebLoadingBehaviorDocumentWriteBlock) &&
!doc_write_block_observed_) {
UMA_HISTOGRAM_BOOLEAN(internal::kHistogramDocWriteBlockCount, true);
LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_BLOCK);
doc_write_block_observed_ = true;
}
if ((info.metadata.behavior_flags &
if ((info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::
WebLoadingBehaviorDocumentWriteBlockDifferentScheme) &&
!doc_write_same_site_diff_scheme_) {
......
......@@ -48,7 +48,7 @@ namespace {
bool IsServiceWorkerControlled(
const page_load_metrics::PageLoadExtraInfo& info) {
return (info.metadata.behavior_flags &
return (info.main_frame_metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::
WebLoadingBehaviorServiceWorkerControlled) != 0;
}
......
......@@ -190,9 +190,9 @@ void SubresourceFilterMetricsObserver::OnLoadingBehaviorObserved(
return;
subresource_filter_observed_ =
(info.metadata.behavior_flags &
blink::WebLoadingBehaviorFlag::
WebLoadingBehaviorSubresourceFilterMatch) != 0;
page_load_metrics::DidObserveLoadingBehaviorInAnyFrame(
info, blink::WebLoadingBehaviorFlag::
WebLoadingBehaviorSubresourceFilterMatch);
if (subresource_filter_observed_) {
UMA_HISTOGRAM_BOOLEAN(internal::kHistogramSubresourceFilterCount, true);
......
......@@ -18,7 +18,8 @@ PageLoadExtraInfo::PageLoadExtraInfo(
PageEndReason page_end_reason,
UserInitiatedInfo page_end_user_initiated_info,
const base::Optional<base::TimeDelta>& page_end_time,
const PageLoadMetadata& metadata)
const PageLoadMetadata& main_frame_metadata,
const PageLoadMetadata& child_frame_metadata)
: navigation_start(navigation_start),
first_background_time(first_background_time),
first_foreground_time(first_foreground_time),
......@@ -30,7 +31,8 @@ PageLoadExtraInfo::PageLoadExtraInfo(
page_end_reason(page_end_reason),
page_end_user_initiated_info(page_end_user_initiated_info),
page_end_time(page_end_time),
metadata(metadata) {}
main_frame_metadata(main_frame_metadata),
child_frame_metadata(child_frame_metadata) {}
PageLoadExtraInfo::PageLoadExtraInfo(const PageLoadExtraInfo& other) = default;
......@@ -48,7 +50,8 @@ PageLoadExtraInfo PageLoadExtraInfo::CreateForTesting(
UserInitiatedInfo::BrowserInitiated(), url, url, true /* did_commit */,
page_load_metrics::END_NONE,
page_load_metrics::UserInitiatedInfo::NotUserInitiated(),
base::TimeDelta(), page_load_metrics::PageLoadMetadata());
base::TimeDelta(), page_load_metrics::PageLoadMetadata(),
page_load_metrics::PageLoadMetadata());
}
ExtraRequestInfo::ExtraRequestInfo(bool was_cached,
......
......@@ -118,7 +118,8 @@ struct PageLoadExtraInfo {
PageEndReason page_end_reason,
UserInitiatedInfo page_end_user_initiated_info,
const base::Optional<base::TimeDelta>& page_end_time,
const PageLoadMetadata& metadata);
const PageLoadMetadata& main_frame_metadata,
const PageLoadMetadata& child_frame_metadata);
// Simplified version of the constructor, intended for use in tests.
static PageLoadExtraInfo CreateForTesting(const GURL& url,
......@@ -186,8 +187,11 @@ struct PageLoadExtraInfo {
const base::Optional<base::TimeDelta> page_end_time;
// Extra information supplied to the page load metrics system from the
// renderer.
const PageLoadMetadata metadata;
// renderer for the main frame.
const PageLoadMetadata main_frame_metadata;
// PageLoadMetadata for child frames of the current page load.
const PageLoadMetadata child_frame_metadata;
};
// Container for various information about a request within a page load.
......@@ -314,7 +318,8 @@ class PageLoadMetricsObserver {
virtual void OnParseStop(const PageLoadTiming& timing,
const PageLoadExtraInfo& extra_info) {}
// Invoked when there is a change in PageLoadMetadata's behavior_flags.
// Invoked when there is a change in either the main_frame_metadata or the
// child_frame_metadata's loading behavior_flags.
virtual void OnLoadingBehaviorObserved(
const page_load_metrics::PageLoadExtraInfo& extra_info) {}
......
......@@ -103,4 +103,14 @@ base::Optional<base::TimeDelta> OptionalMin(
return base::Optional<base::TimeDelta>(std::min(a.value(), b.value()));
}
bool DidObserveLoadingBehaviorInAnyFrame(
const page_load_metrics::PageLoadExtraInfo& info,
blink::WebLoadingBehaviorFlag behavior) {
const int all_frame_loading_behavior_flags =
info.main_frame_metadata.behavior_flags |
info.child_frame_metadata.behavior_flags;
return (all_frame_loading_behavior_flags & behavior) != 0;
}
} // namespace page_load_metrics
......@@ -9,6 +9,7 @@
#include "base/optional.h"
#include "base/time/time.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
#include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h"
// Up to 10 minutes, with 100 buckets.
#define PAGE_LOAD_HISTOGRAM(name, sample) \
......@@ -124,6 +125,12 @@ base::Optional<base::TimeDelta> OptionalMin(
const base::Optional<base::TimeDelta>& a,
const base::Optional<base::TimeDelta>& b);
// Whether the given loading behavior was observed in any frame (either the main
// frame or a child frame).
bool DidObserveLoadingBehaviorInAnyFrame(
const page_load_metrics::PageLoadExtraInfo& info,
blink::WebLoadingBehaviorFlag behavior);
} // namespace page_load_metrics
#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_UTIL_H_
......@@ -255,7 +255,8 @@ void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer,
const PageLoadTiming& new_timing,
const PageLoadMetadata& last_metadata,
const PageLoadExtraInfo& extra_info) {
if (extra_info.metadata.behavior_flags != last_metadata.behavior_flags)
if (extra_info.main_frame_metadata.behavior_flags !=
last_metadata.behavior_flags)
observer->OnLoadingBehaviorObserved(extra_info);
if (last_timing != new_timing)
observer->OnTimingUpdate(new_timing, extra_info);
......@@ -506,6 +507,22 @@ void PageLoadTracker::NotifyClientRedirectTo(
}
}
void PageLoadTracker::UpdateChildFrameMetadata(
const PageLoadMetadata& child_metadata) {
// Merge the child loading behavior flags with any we've already observed,
// possibly from other child frames.
const int last_child_loading_behavior_flags =
child_frame_metadata_.behavior_flags;
child_frame_metadata_.behavior_flags |= child_metadata.behavior_flags;
if (last_child_loading_behavior_flags == child_frame_metadata_.behavior_flags)
return;
PageLoadExtraInfo extra_info(ComputePageLoadExtraInfo());
for (const auto& observer : observers_) {
observer->OnLoadingBehaviorObserved(extra_info);
}
}
bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing,
const PageLoadMetadata& new_metadata) {
// Throw away IPCs that are not relevant to the current navigation.
......@@ -517,22 +534,23 @@ bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing,
timing_.navigation_start == new_timing.navigation_start;
// Ensure flags sent previously are still present in the new metadata fields.
bool valid_behavior_descendent =
(metadata_.behavior_flags & new_metadata.behavior_flags) ==
metadata_.behavior_flags;
(main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) ==
main_frame_metadata_.behavior_flags;
if (IsValidPageLoadTiming(new_timing) && valid_timing_descendent &&
valid_behavior_descendent) {
DCHECK(did_commit_); // OnCommit() must be called first.
// There are some subtle ordering constraints here. GetPageLoadMetricsInfo()
// must be called before DispatchObserverTimingCallbacks, but its
// implementation depends on the state of metadata_, so we need to update
// metadata_ before calling GetPageLoadMetricsInfo. Thus, we make a copy of
// timing here, update timing_ and metadata_, and then proceed to dispatch
// the observer timing callbacks.
// implementation depends on the state of main_frame_metadata_, so we need
// to update main_frame_metadata_ before calling GetPageLoadMetricsInfo.
// Thus, we make a copy of timing here, update timing_ and
// main_frame_metadata_, and then proceed to dispatch the observer timing
// callbacks.
const PageLoadTiming last_timing = timing_;
timing_ = new_timing;
const PageLoadMetadata last_metadata = metadata_;
metadata_ = new_metadata;
const PageLoadMetadata last_metadata = main_frame_metadata_;
main_frame_metadata_ = new_metadata;
const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
for (const auto& observer : observers_) {
DispatchObserverTimingCallbacks(observer.get(), last_timing, new_timing,
......@@ -615,11 +633,11 @@ PageLoadExtraInfo PageLoadTracker::ComputePageLoadExtraInfo() {
(!page_end_user_initiated_info_.browser_initiated &&
!page_end_user_initiated_info_.user_gesture &&
!page_end_user_initiated_info_.user_input_event));
return PageLoadExtraInfo(navigation_start_, first_background_time,
first_foreground_time, started_in_foreground_,
user_initiated_info_, url(), start_url_, did_commit_,
page_end_reason_, page_end_user_initiated_info_,
page_end_time, metadata_);
return PageLoadExtraInfo(
navigation_start_, first_background_time, first_foreground_time,
started_in_foreground_, user_initiated_info_, url(), start_url_,
did_commit_, page_end_reason_, page_end_user_initiated_info_,
page_end_time, main_frame_metadata_, child_frame_metadata_);
}
bool PageLoadTracker::HasMatchingNavigationRequestID(
......
......@@ -107,6 +107,9 @@ enum InternalErrorLoadEvent {
// No page load end time was recorded for this page load.
ERR_NO_PAGE_LOAD_END_TIME,
// Received a timing update from a subframe.
ERR_TIMING_IPC_FROM_SUBFRAME,
// Add values before this final count.
ERR_LAST_ENTRY,
};
......@@ -160,6 +163,11 @@ class PageLoadTracker {
bool UpdateTiming(const PageLoadTiming& timing,
const PageLoadMetadata& metadata);
// Update metadata for child frames. Updates for child frames arrive
// separately from updates for the main frame, so aren't included in
// UpdateTiming.
void UpdateChildFrameMetadata(const PageLoadMetadata& child_metadata);
void OnLoadedResource(const ExtraRequestInfo& extra_request_info);
// Signals that we should stop tracking metrics for the associated page load.
......@@ -294,7 +302,8 @@ class PageLoadTracker {
bool started_in_foreground_;
PageLoadTiming timing_;
PageLoadMetadata metadata_;
PageLoadMetadata main_frame_metadata_;
PageLoadMetadata child_frame_metadata_;
ui::PageTransition page_transition_;
......
......@@ -790,9 +790,12 @@ void ExpectHistogramsAreRecordedForTestFrameSet(
} // namespace
IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
ExpectHistogramsAreRecorded) {
ExpectHistogramsAreRecordedForFilteredChildFrames) {
ASSERT_NO_FATAL_FAILURE(
SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
// Navigate to a URL which doesn't include any filtered resources in the
// top-level document, but which includes filtered resources in child frames.
const GURL url = GetTestUrl(kTestFrameSetPath);
ConfigureAsPhishingURL(url);
......@@ -801,6 +804,14 @@ IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
ExpectHistogramsAreRecordedForTestFrameSet(
tester, false /* expect_performance_measurements */);
// Force a navigation to another page, which flushes page load metrics for the
// previous page load.
ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
// Make sure that pages that have subresource filtered in child frames are
// also counted.
tester.ExpectTotalCount(internal::kHistogramSubresourceFilterCount, 1);
}
IN_PROC_BROWSER_TEST_F(SubresourceFilterWithPerformanceMeasurementBrowserTest,
......
......@@ -519,17 +519,14 @@ void ChromeContentRendererClient::RenderFrameCreated(
new NetErrorHelper(render_frame);
if (render_frame->IsMainFrame()) {
// Only attach MetricsRenderFrameObserver to the main frame, since
// we only want to log page load metrics for the main frame.
new page_load_metrics::MetricsRenderFrameObserver(render_frame);
} else {
new page_load_metrics::MetricsRenderFrameObserver(render_frame);
if (!render_frame->IsMainFrame() &&
prerender::PrerenderHelper::IsPrerendering(
render_frame->GetRenderView()->GetMainRenderFrame())) {
// Avoid any race conditions from having the browser tell subframes that
// they're prerendering.
if (prerender::PrerenderHelper::IsPrerendering(
render_frame->GetRenderView()->GetMainRenderFrame())) {
new prerender::PrerenderHelper(render_frame);
}
new prerender::PrerenderHelper(render_frame);
}
// Set up a mojo service to test if this page is a distiller page.
......
......@@ -38,7 +38,9 @@ MetricsRenderFrameObserver::MetricsRenderFrameObserver(
MetricsRenderFrameObserver::~MetricsRenderFrameObserver() {}
void MetricsRenderFrameObserver::DidChangePerformanceTiming() {
SendMetrics();
// Only track timing metrics for main frames.
if (IsMainFrame())
SendMetrics();
}
void MetricsRenderFrameObserver::DidObserveLoadingBehavior(
......@@ -47,6 +49,10 @@ void MetricsRenderFrameObserver::DidObserveLoadingBehavior(
page_timing_metrics_sender_->DidObserveLoadingBehavior(behavior);
}
void MetricsRenderFrameObserver::FrameDetached() {
page_timing_metrics_sender_.reset();
}
void MetricsRenderFrameObserver::DidCommitProvisionalLoad(
bool is_new_navigation,
bool is_same_page_navigation) {
......@@ -66,8 +72,12 @@ void MetricsRenderFrameObserver::DidCommitProvisionalLoad(
// non-null, we will send metrics for the current page at some later time, as
// those metrics become available.
if (ShouldSendMetrics()) {
PageLoadTiming timing(GetTiming());
DCHECK(!timing.navigation_start.is_null());
PageLoadTiming timing;
if (IsMainFrame()) {
// Only populate PageLoadTiming for the main frame.
timing = GetTiming();
DCHECK(!timing.navigation_start.is_null());
}
page_timing_metrics_sender_.reset(
new PageTimingMetricsSender(this, routing_id(), CreateTimer(), timing));
}
......@@ -86,10 +96,6 @@ bool MetricsRenderFrameObserver::ShouldSendMetrics() const {
if (HasNoRenderFrame())
return false;
const blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
// We only track metrics for main frames.
if (frame->parent())
return false;
const blink::WebDocument& document = frame->document();
return RendererPageTrackDecider(&document, frame->dataSource()).ShouldTrack();
}
......@@ -171,4 +177,8 @@ void MetricsRenderFrameObserver::OnDestruct() {
delete this;
}
bool MetricsRenderFrameObserver::IsMainFrame() const {
return render_frame()->IsMainFrame();
}
} // namespace page_load_metrics
......@@ -20,8 +20,11 @@ namespace page_load_metrics {
class PageTimingMetricsSender;
// MetricsRenderFrameObserver observes RenderFrame notifications, and
// sends page load timing information to the browser process over IPC.
// MetricsRenderFrameObserver observes RenderFrame notifications, and sends page
// load timing information to the browser process over IPC. A
// MetricsRenderFrameObserver is instantiated for each frame (main frames and
// child frames). MetricsRenderFrameObserver dispatches timing and metadata
// updates for main frames, but only metadata updates for child frames.
class MetricsRenderFrameObserver : public content::RenderFrameObserver {
public:
explicit MetricsRenderFrameObserver(content::RenderFrame* render_frame);
......@@ -35,6 +38,10 @@ class MetricsRenderFrameObserver : public content::RenderFrameObserver {
bool is_same_page_navigation) override;
void OnDestruct() override;
// Invoked when a frame is going away. This is our last chance to send IPCs
// before being destroyed.
void FrameDetached() override;
private:
// Will be null when we're not actively sending metrics.
std::unique_ptr<PageTimingMetricsSender> page_timing_metrics_sender_;
......@@ -44,6 +51,7 @@ class MetricsRenderFrameObserver : public content::RenderFrameObserver {
virtual PageLoadTiming GetTiming() const;
virtual std::unique_ptr<base::Timer> CreateTimer() const;
virtual bool HasNoRenderFrame() const;
virtual bool IsMainFrame() const;
DISALLOW_COPY_AND_ASSIGN(MetricsRenderFrameObserver);
};
......
......@@ -41,26 +41,40 @@ class TestMetricsRenderFrameObserver : public MetricsRenderFrameObserver {
mock_timer_ = std::move(timer);
}
void set_is_main_frame(bool is_main_frame) { is_main_frame_ = is_main_frame; }
bool WasFakeTimingConsumed() const { return fake_timing_.IsEmpty(); }
void ExpectPageLoadTiming(const PageLoadTiming& timing) {
SetFakePageLoadTiming(timing);
fake_timing_ipc_sender_.ExpectPageLoadTiming(timing);
}
void SetFakePageLoadTiming(const PageLoadTiming& timing) {
EXPECT_TRUE(fake_timing_.IsEmpty());
fake_timing_ = timing;
}
PageLoadTiming GetTiming() const override {
return fake_timing_ipc_sender_.expected_timings().empty()
? PageLoadTiming()
: fake_timing_ipc_sender_.expected_timings().back();
PageLoadTiming tmp = fake_timing_;
fake_timing_ = PageLoadTiming();
return tmp;
}
void VerifyExpectedTimings() const {
EXPECT_TRUE(fake_timing_.IsEmpty());
fake_timing_ipc_sender_.VerifyExpectedTimings();
}
bool ShouldSendMetrics() const override { return true; }
bool HasNoRenderFrame() const override { return false; }
bool IsMainFrame() const override { return is_main_frame_; }
private:
FakePageTimingMetricsIPCSender fake_timing_ipc_sender_;
mutable PageLoadTiming fake_timing_;
mutable std::unique_ptr<base::Timer> mock_timer_;
bool is_main_frame_ = true;
};
typedef testing::Test MetricsRenderFrameObserverTest;
......@@ -192,4 +206,24 @@ TEST_F(MetricsRenderFrameObserverTest, MultipleNavigations) {
mock_timer2->Fire();
}
TEST_F(MetricsRenderFrameObserverTest, NoUpdatesFromChildFrames) {
base::Time nav_start = base::Time::FromDoubleT(10);
TestMetricsRenderFrameObserver observer;
base::MockTimer* mock_timer = new base::MockTimer(false, false);
observer.set_mock_timer(base::WrapUnique(mock_timer));
observer.set_is_main_frame(false);
PageLoadTiming timing;
timing.navigation_start = nav_start;
observer.SetFakePageLoadTiming(timing);
observer.DidCommitProvisionalLoad(true, false);
ASSERT_FALSE(observer.WasFakeTimingConsumed());
ASSERT_FALSE(mock_timer->IsRunning());
observer.DidChangePerformanceTiming();
ASSERT_FALSE(observer.WasFakeTimingConsumed());
ASSERT_FALSE(mock_timer->IsRunning());
}
} // namespace page_load_metrics
......@@ -29,8 +29,10 @@ PageTimingMetricsSender::PageTimingMetricsSender(
timer_(std::move(timer)),
last_timing_(initial_timing),
metadata_(PageLoadMetadata()) {
// Send an initial IPC relatively early to help track aborts.
EnsureSendTimer(kInitialTimerDelayMillis);
if (!initial_timing.IsEmpty()) {
// Send an initial IPC relatively early to help track aborts.
EnsureSendTimer(kInitialTimerDelayMillis);
}
}
// On destruction, we want to send any data we have if we have a timer
......
......@@ -245,14 +245,14 @@ void DocumentLoader::dispatchLinkHeaderPreloads(
}
void DocumentLoader::didChangePerformanceTiming() {
if (m_frame && m_frame->isMainFrame() && m_state >= Committed) {
if (m_frame && m_state >= Committed) {
localFrameClient().didChangePerformanceTiming();
}
}
void DocumentLoader::didObserveLoadingBehavior(
WebLoadingBehaviorFlag behavior) {
if (m_frame && m_frame->isMainFrame()) {
if (m_frame) {
DCHECK_GE(m_state, Committed);
localFrameClient().didObserveLoadingBehavior(behavior);
}
......
......@@ -97289,6 +97289,7 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
<int value="8" label="Inter process TimeTicks skew"/>
<int value="9" label="No commit or failed provisional load received"/>
<int value="10" label="No page load end time recorded"/>
<int value="11" label="Timing IPC received from subframe"/>
</enum>
<enum name="InterruptReason" type="int">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment