Index: chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc |
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc |
index f6a08a182e620ff14f156528597e3cf507d7550c..cb4ad34eb17a622ce00c2c42f48422321c4145cb 100644 |
--- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc |
+++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc |
@@ -23,25 +23,37 @@ const base::Feature kAdsFeature{"AdsMetrics", |
base::FEATURE_DISABLED_BY_DEFAULT}; |
bool FrameIsAd(content::NavigationHandle* navigation_handle) { |
- content::RenderFrameHost* current_frame_host = |
- navigation_handle->GetRenderFrameHost(); |
- DCHECK(current_frame_host); |
- const std::string& name = current_frame_host->GetFrameName(); |
- const GURL& url = navigation_handle->GetURL(); |
- |
// Because sub-resource filtering isn't always enabled, and doesn't work |
// well in monitoring mode (no CSS enforcement), it's difficult to identify |
// ads. Google ads are prevalent and easy to track, so we'll start by |
// tracking those. Note that the frame name can be very large, so be careful |
// to avoid full string searches if possible. |
// TODO(jkarlin): Track other ad networks that are easy to identify. |
- return base::StartsWith(name, "google_ads_iframe", |
- base::CompareCase::SENSITIVE) || |
- base::StartsWith(name, "google_ads_frame", |
- base::CompareCase::SENSITIVE) || |
- (url.host_piece() == "tpc.googlesyndication.com" && |
- base::StartsWith(url.path_piece(), "/safeframe", |
- base::CompareCase::SENSITIVE)); |
+ |
+ // In case the navigation aborted, look up the RFH by the Frame Tree Node |
+ // ID. It returns the committed frame host or the initial frame host for the |
+ // frame if no committed host exists. Using a previous host is fine because |
+ // once a frame has an ad we always consider it to have an ad. |
+ // We use the unsafe method of FindFrameByFrameTreeNodeId because we're not |
+ // concerned with which process the frame lives on (we're just measuring |
+ // bytes and not granting security priveleges). |
+ content::RenderFrameHost* current_frame_host = |
+ navigation_handle->GetWebContents()->UnsafeFindFrameByFrameTreeNodeId( |
+ navigation_handle->GetFrameTreeNodeId()); |
+ if (current_frame_host) { |
+ const std::string& frame_name = current_frame_host->GetFrameName(); |
+ if (base::StartsWith(frame_name, "google_ads_iframe", |
+ base::CompareCase::SENSITIVE) || |
+ base::StartsWith(frame_name, "google_ads_frame", |
+ base::CompareCase::SENSITIVE)) { |
+ return true; |
+ } |
+ } |
+ |
+ const GURL& url = navigation_handle->GetURL(); |
+ return url.host_piece() == "tpc.googlesyndication.com" && |
+ base::StartsWith(url.path_piece(), "/safeframe", |
+ base::CompareCase::SENSITIVE); |
} |
} // namespace |
@@ -77,22 +89,13 @@ AdsPageLoadMetricsObserver::OnCommit( |
page_load_metrics::PageLoadMetricsObserver::ObservePolicy |
AdsPageLoadMetricsObserver::OnDidFinishSubFrameNavigation( |
content::NavigationHandle* navigation_handle) { |
+ // Determine if the frame is part of an existing ad, the root of a new ad, |
+ // or a non-ad frame. Once a frame is labled as an ad, it is always |
+ // considered an ad, even if it navigates to a non-ad page. This function |
+ // labels all of a page's frames, even those that fail to commit. |
FrameTreeNodeId frame_tree_node_id = navigation_handle->GetFrameTreeNodeId(); |
- |
- if (!navigation_handle->HasCommitted() || |
- navigation_handle->IsSameDocument() || navigation_handle->IsErrorPage()) { |
- // We're not interested in tracking this navigation. In case we've seen a |
- // resource for the navigation before this message, clear it from |
- // ongoing_navigation_resources_. |
- ongoing_navigation_resources_.erase(frame_tree_node_id); |
- return CONTINUE_OBSERVING; |
- } |
- |
content::RenderFrameHost* parent_frame_host = |
- navigation_handle->GetRenderFrameHost()->GetParent(); |
- DCHECK(parent_frame_host); |
- |
- bool top_level_subframe = !parent_frame_host->GetParent(); |
+ navigation_handle->GetParentFrame(); |
const auto& id_and_data = ad_frames_data_.find(frame_tree_node_id); |
if (id_and_data != ad_frames_data_.end()) { |
@@ -107,7 +110,6 @@ AdsPageLoadMetricsObserver::OnDidFinishSubFrameNavigation( |
"PageLoad.Clients.Ads.Google.Navigations.AdFrameRenavigatedToAd", |
FrameIsAd(navigation_handle)); |
} |
- |
return CONTINUE_OBSERVING; |
} |
// This frame was previously not an ad, process it as usual. If it had |
@@ -115,7 +117,7 @@ AdsPageLoadMetricsObserver::OnDidFinishSubFrameNavigation( |
UMA_HISTOGRAM_BOOLEAN( |
"PageLoad.Clients.Ads.Google.Navigations.NonAdFrameRenavigatedToAd", |
FrameIsAd(navigation_handle)); |
- } else if (top_level_subframe) { |
+ } else if (navigation_handle->IsParentMainFrame()) { |
top_level_subframe_count_ += 1; |
} |
@@ -133,7 +135,7 @@ AdsPageLoadMetricsObserver::OnDidFinishSubFrameNavigation( |
ad_frames_data_[frame_tree_node_id] = ad_data; |
- if (top_level_subframe && ad_data) |
+ if (navigation_handle->IsParentMainFrame() && ad_data) |
top_level_ad_frame_count_ += 1; |
ProcessOngoingNavigationResource(frame_tree_node_id); |
@@ -176,12 +178,13 @@ void AdsPageLoadMetricsObserver::ProcessLoadedResource( |
const auto& id_and_data = |
ad_frames_data_.find(extra_request_info.frame_tree_node_id); |
if (id_and_data == ad_frames_data_.end()) { |
- // This resouce is for a frame that hasn't yet committed. It must be the |
- // main document for the frame. Hold onto it and once it commits we'll run |
- // it in ProcessOngoingNavigationResource. |
- // TODO(jkarlin): Plumb the resource type through and DCHECK that the type |
- // is document. |
- auto it_and_success = ongoing_navigation_resources_.emplace( |
+ // This resource is for a frame that hasn't ever finished a navigation. We |
+ // expect it to be the frame's main resource but don't have enough |
+ // confidence in that to dcheck it. For example, there might be races |
+ // between doc.written resources and navigation failure. |
+ // TODO(jkarlin): Add UMA to measure how often we see multiple resources |
+ // for a frame before navigation finishes. |
+ ongoing_navigation_resources_.emplace( |
std::piecewise_construct, |
std::forward_as_tuple(extra_request_info.frame_tree_node_id), |
std::forward_as_tuple( |
@@ -189,7 +192,6 @@ void AdsPageLoadMetricsObserver::ProcessLoadedResource( |
extra_request_info.was_cached, extra_request_info.raw_body_bytes, |
extra_request_info.original_network_content_length, nullptr, |
extra_request_info.resource_type)); |
- DCHECK(it_and_success.second); |
return; |
} |