OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/page_load_metrics/observers/ads_page_load_metrics_obser ver.h" | |
6 | |
7 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" | |
8 #include "content/public/browser/render_frame_host.h" | |
9 #include "content/public/browser/web_contents.h" | |
10 | |
11 namespace { | |
12 | |
13 bool FrameIsAd(content::NavigationHandle* navigation_handle) { | |
14 int frame_tree_node_id = navigation_handle->GetFrameTreeNodeId(); | |
15 content::RenderFrameHost* current_frame_host = | |
16 navigation_handle->GetWebContents()->FindFrameByFrameTreeNodeId( | |
17 frame_tree_node_id); | |
18 const std::string& name = current_frame_host->GetFrameName(); | |
19 const std::string& url_spec = navigation_handle->GetURL().spec(); | |
20 | |
21 return base::StartsWith(name, "google_ads_iframe", | |
ojan
2017/04/07 19:40:06
People will stumble across this in public. Anywher
jkarlin
2017/04/10 17:52:23
Done.
| |
22 base::CompareCase::SENSITIVE) || | |
23 base::StartsWith(name, "google_ads_frame", | |
24 base::CompareCase::SENSITIVE) || | |
25 base::StartsWith(url_spec, | |
26 "http://tpc.googlesyndication.com/safeframe/", | |
27 base::CompareCase::SENSITIVE) || | |
28 base::StartsWith(url_spec, | |
29 "https://tpc.googlesyndication.com/safeframe/", | |
30 base::CompareCase::SENSITIVE); | |
31 } | |
32 | |
33 } // namespace | |
34 | |
35 AdsPageLoadMetricsObserver::AdsPageLoadMetricsObserver() = default; | |
36 AdsPageLoadMetricsObserver::~AdsPageLoadMetricsObserver() = default; | |
37 | |
38 page_load_metrics::PageLoadMetricsObserver::ObservePolicy | |
39 AdsPageLoadMetricsObserver::OnCommit( | |
40 content::NavigationHandle* navigation_handle) { | |
41 DCHECK(ad_frames_.empty()); | |
42 DCHECK(ad_ancestors_.empty()); | |
43 | |
44 // The main frame is never considered an ad. | |
45 ad_ancestors_[navigation_handle->GetFrameTreeNodeId()] = | |
46 kInvalidFrameTreeNodeId; | |
47 ProcessDelayedResources(navigation_handle->GetFrameTreeNodeId()); | |
48 return CONTINUE_OBSERVING; | |
49 } | |
50 | |
51 page_load_metrics::PageLoadMetricsObserver::ObservePolicy | |
52 AdsPageLoadMetricsObserver::OnCommitSubFrame( | |
53 content::NavigationHandle* navigation_handle) { | |
54 DCHECK( | |
55 !base::ContainsKey(ad_frames_, navigation_handle->GetFrameTreeNodeId())); | |
56 | |
57 FrameTreeNodeId frame_tree_node_id = navigation_handle->GetFrameTreeNodeId(); | |
58 FrameTreeNodeId ancestor_id = FindAdAncestor(navigation_handle); | |
59 | |
60 if (ancestor_id != kInvalidFrameTreeNodeId) { | |
61 ad_ancestors_[frame_tree_node_id] = ancestor_id; | |
62 ProcessDelayedResources(frame_tree_node_id); | |
63 return CONTINUE_OBSERVING; | |
64 } | |
65 | |
66 if (FrameIsAd(navigation_handle)) { | |
67 ad_frames_[frame_tree_node_id] = AdFrameData(); | |
68 ad_ancestors_[frame_tree_node_id] = frame_tree_node_id; | |
69 ProcessDelayedResources(frame_tree_node_id); | |
70 return CONTINUE_OBSERVING; | |
71 } | |
72 | |
73 ad_ancestors_[frame_tree_node_id] = kInvalidFrameTreeNodeId; | |
74 ProcessDelayedResources(frame_tree_node_id); | |
75 return CONTINUE_OBSERVING; | |
76 } | |
77 | |
78 void AdsPageLoadMetricsObserver::OnLoadedResource( | |
79 const page_load_metrics::ExtraRequestInfo& extra_request_info) { | |
80 if (!base::ContainsKey(ad_ancestors_, | |
81 extra_request_info.frame_tree_node_id)) { | |
82 // This resouce is for a frame that hasn't yet committed. It must be the | |
83 // main document for the frame. Hold onto it and once it commits we'll run | |
84 // it in ProcessDelayedResources. | |
85 auto it_and_success = delayed_resources_.insert(std::make_pair( | |
86 extra_request_info.frame_tree_node_id, extra_request_info)); | |
87 DCHECK(it_and_success.second); | |
88 return; | |
89 } | |
90 | |
91 page_bytes_ += extra_request_info.raw_body_bytes; | |
92 if (!extra_request_info.was_cached) | |
93 uncached_page_bytes_ += extra_request_info.raw_body_bytes; | |
94 | |
95 // Determine if the frame (or its ancestor) is an ad, if so attribute the | |
96 // bytes to the highest ad ancestor. | |
97 FrameTreeNodeId ad_ancestor_id = | |
98 ad_ancestors_[extra_request_info.frame_tree_node_id]; | |
99 if (ad_ancestor_id != kInvalidFrameTreeNodeId) { | |
100 ad_frames_[ad_ancestor_id].frame_bytes += extra_request_info.raw_body_bytes; | |
101 if (!extra_request_info.was_cached) | |
102 ad_frames_[ad_ancestor_id].frame_bytes_uncached += | |
103 extra_request_info.raw_body_bytes; | |
104 } | |
105 } | |
106 | |
107 void AdsPageLoadMetricsObserver::OnComplete( | |
ojan
2017/04/07 19:40:06
Do you also need to hook FlushMetricsOnAppEnterBac
jkarlin
2017/04/10 17:52:23
Good idea. Done.
| |
108 const page_load_metrics::PageLoadTiming& timing, | |
109 const page_load_metrics::PageLoadExtraInfo& info) { | |
110 if (page_bytes_ == 0) | |
111 return; | |
112 | |
113 size_t total_ad_frame_bytes = 0; | |
114 size_t uncached_ad_frame_bytes = 0; | |
115 int ad_frames = 0; | |
116 | |
117 for (const auto& frame_id_and_size : ad_frames_) { | |
118 total_ad_frame_bytes += frame_id_and_size.second.frame_bytes; | |
119 uncached_ad_frame_bytes += frame_id_and_size.second.frame_bytes_uncached; | |
120 | |
121 const AdFrameData& data = frame_id_and_size.second; | |
122 if (data.frame_bytes > 0) { | |
123 ad_frames += 1; | |
124 PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Google.Bytes.AdFrame", | |
125 data.frame_bytes); | |
126 PAGE_BYTES_HISTOGRAM( | |
127 "PageLoad.Clients.Ads.Google.Bytes.AdFrameFromNetwork", | |
128 data.frame_bytes_uncached); | |
129 UMA_HISTOGRAM_PERCENTAGE( | |
130 "PageLoad.Experimental.Ads.Google.BytesPercent.AdFrameFromNetwork", | |
131 data.frame_bytes_uncached * 100 / data.frame_bytes); | |
132 } | |
133 } | |
134 | |
135 // Don't post UMA for pages that don't have ads or content. | |
136 if (total_ad_frame_bytes == 0) { | |
137 UMA_HISTOGRAM_COUNTS("PageLoad.Clients.Ads.Google.PageHasNoAds", 1); | |
138 return; | |
139 } | |
140 | |
141 PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Google.Bytes.AdFrames", | |
142 total_ad_frame_bytes); | |
143 | |
144 PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Google.Bytes.PageSansAdFrames", | |
145 page_bytes_ - total_ad_frame_bytes); | |
146 | |
147 PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Google.Bytes.Page", page_bytes_); | |
148 PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Google.Bytes.PageFromNetwork", | |
149 uncached_page_bytes_); | |
150 | |
151 UMA_HISTOGRAM_PERCENTAGE( | |
152 "PageLoad.Experimental.Ads.Google.BytesPercent.AdFrames", | |
153 total_ad_frame_bytes * 100 / page_bytes_); | |
154 | |
155 UMA_HISTOGRAM_COUNTS_1000("PageLoad.Clients.Ads.Google.AdFrameCount", | |
156 ad_frames); | |
157 | |
158 PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Google.Bytes.AdFramesFromNetwork", | |
159 uncached_ad_frame_bytes); | |
160 | |
161 UMA_HISTOGRAM_PERCENTAGE( | |
162 "PageLoad.Experimental.Ads.Google.BytesPercent." | |
163 "AdFramesFromNetworkOfAdFramesTotal", | |
164 uncached_ad_frame_bytes * 100 / total_ad_frame_bytes); | |
165 | |
166 int percent_bytes_from_uncached_ads = | |
167 uncached_page_bytes_ == 0 | |
168 ? 0 | |
169 : uncached_ad_frame_bytes * 100 / uncached_page_bytes_; | |
170 UMA_HISTOGRAM_PERCENTAGE( | |
171 "PageLoad.Clients.Ads.Google.Bytes.Percent." | |
172 "AdFramesFromNetworkOfPageFromNetwork", | |
173 percent_bytes_from_uncached_ads); | |
174 } | |
175 | |
176 int AdsPageLoadMetricsObserver::FindAdAncestor( | |
177 content::NavigationHandle* navigation_handle) { | |
178 // We haven't seen a load from this frame before. We should have seen its | |
179 // parent though. Use the ad ancestor of its parent. | |
180 content::RenderFrameHost* parent_frame_host = | |
181 navigation_handle->GetRenderFrameHost()->GetParent(); | |
182 DCHECK(parent_frame_host); // Since this isn't a main frame. | |
183 DCHECK(base::ContainsKey(ad_ancestors_, | |
184 parent_frame_host->GetFrameTreeNodeId())); | |
185 return ad_ancestors_[parent_frame_host->GetFrameTreeNodeId()]; | |
186 } | |
187 | |
188 void AdsPageLoadMetricsObserver::ProcessDelayedResources( | |
189 FrameTreeNodeId frame_tree_node_id) { | |
190 const auto& frame_id_and_request = | |
191 delayed_resources_.find(frame_tree_node_id); | |
192 if (frame_id_and_request == delayed_resources_.end()) | |
193 return; | |
194 OnLoadedResource(frame_id_and_request->second); | |
195 } | |
OLD | NEW |