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

Side by Side Diff: chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc

Issue 2534023002: Create a DataUseRecorder instance for each page load in Chrome. (Closed)
Patch Set: Addressed comments Created 4 years 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/data_use_measurement/chrome_data_use_ascriber.h" 5 #include "chrome/browser/data_use_measurement/chrome_data_use_ascriber.h"
6 6
7 #include <string>
8
7 #include "base/memory/ptr_util.h" 9 #include "base/memory/ptr_util.h"
10 #include "chrome/browser/data_use_measurement/chrome_data_use_recorder.h"
8 #include "components/data_use_measurement/content/content_url_request_classifier .h" 11 #include "components/data_use_measurement/content/content_url_request_classifier .h"
9 #include "components/data_use_measurement/core/data_use_recorder.h" 12 #include "components/data_use_measurement/core/data_use_recorder.h"
10 #include "components/data_use_measurement/core/data_use_user_data.h" 13 #include "components/data_use_measurement/core/data_use_user_data.h"
11 #include "components/data_use_measurement/core/url_request_classifier.h" 14 #include "components/data_use_measurement/core/url_request_classifier.h"
12 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/navigation_handle.h" 16 #include "content/public/browser/navigation_handle.h"
14 #include "content/public/browser/render_frame_host.h" 17 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/resource_request_info.h" 18 #include "content/public/browser/resource_request_info.h"
16 #include "content/public/common/browser_side_navigation_policy.h" 19 #include "content/public/common/browser_side_navigation_policy.h"
20 #include "ipc/ipc_message.h"
17 #include "net/url_request/url_request.h" 21 #include "net/url_request/url_request.h"
18 22
19 namespace data_use_measurement { 23 namespace data_use_measurement {
20 24
21 // static 25 // static
22 const void* ChromeDataUseAscriber::DataUseRecorderEntryAsUserData:: 26 const void* ChromeDataUseAscriber::DataUseRecorderEntryAsUserData::
23 kUserDataKey = static_cast<void*>( 27 kUserDataKey = static_cast<void*>(
24 &ChromeDataUseAscriber::DataUseRecorderEntryAsUserData::kUserDataKey); 28 &ChromeDataUseAscriber::DataUseRecorderEntryAsUserData::kUserDataKey);
25 29
26 ChromeDataUseAscriber::DataUseRecorderEntryAsUserData:: 30 ChromeDataUseAscriber::DataUseRecorderEntryAsUserData::
27 DataUseRecorderEntryAsUserData(DataUseRecorderEntry entry) 31 DataUseRecorderEntryAsUserData(DataUseRecorderEntry entry)
28 : entry_(entry) {} 32 : entry_(entry) {}
29 33
30 ChromeDataUseAscriber::DataUseRecorderEntryAsUserData:: 34 ChromeDataUseAscriber::DataUseRecorderEntryAsUserData::
31 ~DataUseRecorderEntryAsUserData() {} 35 ~DataUseRecorderEntryAsUserData() {}
32 36
33 ChromeDataUseAscriber::ChromeDataUseAscriber() { 37 ChromeDataUseAscriber::ChromeDataUseAscriber() {
34 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 38 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
35 } 39 }
36 40
37 ChromeDataUseAscriber::~ChromeDataUseAscriber() { 41 ChromeDataUseAscriber::~ChromeDataUseAscriber() {
38 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 42 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
39 DCHECK_EQ(0u, data_use_recorders_.size()); 43 DCHECK_EQ(0u, data_use_recorders_.size());
40 } 44 }
41 45
42 DataUseRecorder* ChromeDataUseAscriber::GetDataUseRecorder( 46 ChromeDataUseRecorder* ChromeDataUseAscriber::GetDataUseRecorder(
43 net::URLRequest* request) { 47 net::URLRequest* request,
48 bool can_create_new) {
49 DataUseRecorderEntry entry = GetDataUseRecorderEntry(request, can_create_new);
50 return entry == data_use_recorders_.end() ? nullptr : &(*entry);
51 }
52
53 ChromeDataUseAscriber::DataUseRecorderEntry
54 ChromeDataUseAscriber::GetDataUseRecorderEntry(net::URLRequest* request,
55 bool can_create_new) {
44 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 56 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
45 return nullptr; 57
58 // TODO(ryansturm): Handle PlzNavigate (http://crbug/664233).
59 if (content::IsBrowserSideNavigationEnabled())
60 return data_use_recorders_.end();
61
62 // If a DataUseRecorder has already been set as user data, then return that.
63 auto user_data = static_cast<DataUseRecorderEntryAsUserData*>(
64 request->GetUserData(DataUseRecorderEntryAsUserData::kUserDataKey));
65 if (user_data)
66 return user_data->recorder_entry();
67
68 if (!can_create_new)
69 return data_use_recorders_.end();
70
71 // If request is associated with a ChromeService, create a new
72 // DataUseRecorder for it. There is no reason to aggregate URLRequests
73 // from ChromeServices into the same DataUseRecorder instance.
74 DataUseUserData* service = static_cast<DataUseUserData*>(
75 request->GetUserData(DataUseUserData::kUserDataKey));
76 if (service) {
77 DataUseRecorderEntry entry = CreateNewDataUseRecorder(request);
78
79 entry->data_use().set_description(
80 DataUseUserData::GetServiceNameAsString(service->service_name()));
81 return entry;
82 }
83
84 int render_process_id = -1;
85 int render_frame_id = -1;
86 bool has_valid_frame = content::ResourceRequestInfo::GetRenderFrameForRequest(
87 request, &render_process_id, &render_frame_id);
88 if (has_valid_frame &&
89 render_frame_id != SpecialRoutingIDs::MSG_ROUTING_NONE) {
90 DCHECK(render_process_id >= 0 || render_frame_id >= 0);
91
92 // Browser tests may not set up DataUseWebContentsObservers in which case
93 // this class never sees navigation and frame events so DataUseRecorders
94 // will never be destroyed. To avoid this, we ignore requests whose
95 // render frames don't have a record. However, this can also be caused by
96 // URLRequests racing the frame create events.
97 // TODO(kundaji): Add UMA.
98 RenderFrameHostID frame_key(render_process_id, render_frame_id);
99 auto frame_iter = render_frame_data_use_map_.find(frame_key);
100 if (frame_iter == render_frame_data_use_map_.end()) {
101 return data_use_recorders_.end();
102 }
103
104 const content::ResourceRequestInfo* request_info =
105 content::ResourceRequestInfo::ForRequest(request);
106 content::ResourceType resource_type =
107 request_info ? request_info->GetResourceType()
108 : content::RESOURCE_TYPE_LAST_TYPE;
109
110 if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
111 content::GlobalRequestID navigation_key =
112 request_info->GetGlobalRequestID();
113
114 DataUseRecorderEntry new_entry = CreateNewDataUseRecorder(request);
115 new_entry->set_main_frame_request_id(navigation_key);
116 pending_navigation_data_use_map_.insert(
117 std::make_pair(navigation_key, new_entry));
118
119 return new_entry;
120 }
121
122 DCHECK(frame_iter != render_frame_data_use_map_.end());
123 auto entry = frame_iter->second;
124 request->SetUserData(DataUseRecorderEntryAsUserData::kUserDataKey,
125 new DataUseRecorderEntryAsUserData(entry));
126 entry->AddPendingURLRequest(request);
127 return entry;
128 }
129
130 // Create a new DataUseRecorder for all other requests.
131 DataUseRecorderEntry entry = CreateNewDataUseRecorder(request);
132 DataUse& data_use = entry->data_use();
133 data_use.set_url(request->url());
134 return entry;
46 } 135 }
47 136
48 void ChromeDataUseAscriber::OnBeforeUrlRequest(net::URLRequest* request) { 137 void ChromeDataUseAscriber::OnBeforeUrlRequest(net::URLRequest* request) {
49 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 138 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
139 DataUseAscriber::OnBeforeUrlRequest(request);
50 140
51 // TODO(kundaji): Handle PlzNavigate. 141 // TODO(kundaji): Handle PlzNavigate.
52 if (content::IsBrowserSideNavigationEnabled()) 142 if (content::IsBrowserSideNavigationEnabled())
53 return; 143 return;
54 144
55 auto service = static_cast<DataUseUserData*>( 145 auto service = static_cast<DataUseUserData*>(
56 request->GetUserData(DataUseUserData::kUserDataKey)); 146 request->GetUserData(DataUseUserData::kUserDataKey));
57 if (service) 147 if (service)
58 return; 148 return;
59 149
(...skipping 24 matching lines...) Expand all
84 return; 174 return;
85 } 175 }
86 176
87 // If this request is already being tracked, do not create a new entry. 177 // If this request is already being tracked, do not create a new entry.
88 auto user_data = static_cast<DataUseRecorderEntryAsUserData*>( 178 auto user_data = static_cast<DataUseRecorderEntryAsUserData*>(
89 request->GetUserData(DataUseRecorderEntryAsUserData::kUserDataKey)); 179 request->GetUserData(DataUseRecorderEntryAsUserData::kUserDataKey));
90 if (user_data) 180 if (user_data)
91 return; 181 return;
92 182
93 DataUseRecorderEntry entry = data_use_recorders_.insert( 183 DataUseRecorderEntry entry = data_use_recorders_.insert(
94 data_use_recorders_.end(), base::MakeUnique<DataUseRecorder>()); 184 data_use_recorders_.end(), ChromeDataUseRecorder());
95 request->SetUserData(DataUseRecorderEntryAsUserData::kUserDataKey, 185 request->SetUserData(DataUseRecorderEntryAsUserData::kUserDataKey,
96 new DataUseRecorderEntryAsUserData(entry)); 186 new DataUseRecorderEntryAsUserData(entry));
97 pending_navigation_data_use_map_.insert( 187 pending_navigation_data_use_map_.insert(
98 std::make_pair(request_info->GetGlobalRequestID(), entry)); 188 std::make_pair(request_info->GetGlobalRequestID(), entry));
99 } 189 }
100 190
101 void ChromeDataUseAscriber::OnUrlRequestDestroyed(net::URLRequest* request) { 191 void ChromeDataUseAscriber::OnUrlRequestDestroyed(net::URLRequest* request) {
192 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
193
194 DataUseRecorderEntry entry = GetDataUseRecorderEntry(request, true);
195
196 if (entry == data_use_recorders_.end())
197 return;
198
199 DataUseRecorder* recorder = &(*entry);
200
201 RenderFrameHostID frame_key = entry->main_frame_id();
202 auto frame_iter = render_frame_data_use_map_.find(frame_key);
203 bool is_in_render_frame_map =
204 frame_iter != render_frame_data_use_map_.end() &&
205 frame_iter->second->HasPendingURLRequest(request);
206
102 const content::ResourceRequestInfo* request_info = 207 const content::ResourceRequestInfo* request_info =
103 content::ResourceRequestInfo::ForRequest(request); 208 content::ResourceRequestInfo::ForRequest(request);
104 content::ResourceType resource_type = request_info 209 content::ResourceType resource_type = request_info
105 ? request_info->GetResourceType() 210 ? request_info->GetResourceType()
106 : content::RESOURCE_TYPE_LAST_TYPE; 211 : content::RESOURCE_TYPE_LAST_TYPE;
107 if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) { 212
108 // If request was not successful, then ReadyToCommitNavigation will not be 213 bool is_in_pending_navigation_map = false;
109 // called. So delete the pending navigation DataUseRecorderEntry here. 214 if (request_info && resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
110 if (!request->status().is_success()) { 215 auto navigation_iter = pending_navigation_data_use_map_.find(
111 DeletePendingNavigationEntry(request_info->GetGlobalRequestID()); 216 entry->main_frame_request_id());
217 is_in_pending_navigation_map =
218 navigation_iter != pending_navigation_data_use_map_.end();
219
220 // If request was not successful, then NavigationHandle in
221 // DidFinishMainFrameNavigation will not have GlobalRequestID. So we erase
222 // the DataUseRecorderEntry here.
223 if (is_in_pending_navigation_map && !request->status().is_success()) {
224 pending_navigation_data_use_map_.erase(navigation_iter);
225 is_in_pending_navigation_map = false;
112 } 226 }
113 } 227 }
228
229 DataUseAscriber::OnUrlRequestDestroyed(request);
230 request->RemoveUserData(DataUseRecorderEntryAsUserData::kUserDataKey);
231
232 if (recorder->IsDataUseComplete() && !is_in_render_frame_map &&
233 !is_in_pending_navigation_map) {
234 OnDataUseCompleted(entry);
235 data_use_recorders_.erase(entry);
236 }
114 } 237 }
115 238
116 void ChromeDataUseAscriber::RenderFrameCreated(int render_process_id, 239 void ChromeDataUseAscriber::RenderFrameCreated(int render_process_id,
117 int render_frame_id, 240 int render_frame_id,
118 int parent_render_process_id, 241 int parent_render_process_id,
119 int parent_render_frame_id) { 242 int parent_render_frame_id) {
120 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 243 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
121 244
122 // TODO(kundaji): Point child render frames to the same DataUseRecorder as 245 if (content::IsBrowserSideNavigationEnabled())
123 // parent render frame. 246 return;
124 DataUseRecorderEntry entry = data_use_recorders_.insert( 247
125 data_use_recorders_.end(), base::MakeUnique<DataUseRecorder>()); 248 if (parent_render_process_id != -1 && parent_render_frame_id != -1) {
126 render_frame_data_use_map_.insert(std::make_pair( 249 // Create an entry in |render_frame_data_use_map_| for this frame with
127 RenderFrameHostID(render_process_id, render_frame_id), entry)); 250 // the same DataUseRecorderEntry as its parent frame.
251 auto frame_iter = render_frame_data_use_map_.find(
252 RenderFrameHostID(parent_render_process_id, parent_render_frame_id));
253
254 DCHECK(frame_iter != render_frame_data_use_map_.end());
255
256 DataUseRecorderEntry entry = frame_iter->second;
257 render_frame_data_use_map_.insert(std::make_pair(
258 RenderFrameHostID(render_process_id, render_frame_id), entry));
259 } else {
260 auto frame_iter = render_frame_data_use_map_.find(
261 RenderFrameHostID(render_process_id, render_frame_id));
262 DCHECK(frame_iter == render_frame_data_use_map_.end());
263 DataUseRecorderEntry entry = CreateNewDataUseRecorder(nullptr);
264 entry->set_main_frame_id(
265 RenderFrameHostID(render_process_id, render_frame_id));
266 render_frame_data_use_map_.insert(std::make_pair(
267 RenderFrameHostID(render_process_id, render_frame_id), entry));
268 }
128 } 269 }
129 270
130 void ChromeDataUseAscriber::RenderFrameDeleted(int render_process_id, 271 void ChromeDataUseAscriber::RenderFrameDeleted(int render_process_id,
131 int render_frame_id, 272 int render_frame_id,
132 int parent_render_process_id, 273 int parent_render_process_id,
133 int parent_render_frame_id) { 274 int parent_render_frame_id) {
134 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 275 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
276
277 if (content::IsBrowserSideNavigationEnabled())
278 return;
279
135 RenderFrameHostID key(render_process_id, render_frame_id); 280 RenderFrameHostID key(render_process_id, render_frame_id);
136 auto frame_iter = render_frame_data_use_map_.find(key); 281 auto frame_iter = render_frame_data_use_map_.find(key);
282
137 DCHECK(frame_iter != render_frame_data_use_map_.end()); 283 DCHECK(frame_iter != render_frame_data_use_map_.end());
284
138 DataUseRecorderEntry entry = frame_iter->second; 285 DataUseRecorderEntry entry = frame_iter->second;
286 DataUseRecorder* recorder = &(*entry);
287
288 if (parent_render_process_id == -1 && parent_render_frame_id == -1 &&
289 recorder->IsDataUseComplete()) {
290 OnDataUseCompleted(entry);
291 data_use_recorders_.erase(entry);
292 }
293
139 render_frame_data_use_map_.erase(frame_iter); 294 render_frame_data_use_map_.erase(frame_iter);
140
141 data_use_recorders_.erase(entry);
142 } 295 }
143 296
144 void ChromeDataUseAscriber::DidStartMainFrameNavigation( 297 void ChromeDataUseAscriber::DidStartMainFrameNavigation(
145 GURL gurl, 298 GURL gurl,
146 int render_process_id, 299 int render_process_id,
147 int render_frame_id, 300 int render_frame_id,
148 void* navigation_handle) { 301 void* navigation_handle) {
149 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 302 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
150 } 303 }
151 304
152 void ChromeDataUseAscriber::ReadyToCommitMainFrameNavigation( 305 void ChromeDataUseAscriber::ReadyToCommitMainFrameNavigation(
153 GURL gurl, 306 GURL gurl,
154 content::GlobalRequestID global_request_id, 307 content::GlobalRequestID global_request_id,
155 int render_process_id, 308 int render_process_id,
156 int render_frame_id, 309 int render_frame_id,
157 bool is_same_page_navigation, 310 bool is_same_page_navigation,
158 void* navigation_handle) { 311 void* navigation_handle) {
159 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 312 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
160 313
161 // TODO(kundaji): Move the DataUseRecorderEntry from pending navigation map 314 // Find the DataUseRecorderEntry the frame is associated with
162 // to render frame map if |is_same_page_navigation| is true. Otherwise, 315 auto frame_it = render_frame_data_use_map_.find(
163 // merge it with the DataUseRecorderEntry in the render frame map. 316 RenderFrameHostID(render_process_id, render_frame_id));
164 DeletePendingNavigationEntry(global_request_id); 317
318 // Find the pending navigation entry.
319 auto navigation_iter =
320 pending_navigation_data_use_map_.find(global_request_id);
321 // We might not find a navigation entry since the pending navigation may not
322 // have caused any HTTP or HTTPS URLRequests to be made.
323 if (navigation_iter == pending_navigation_data_use_map_.end()) {
324 // No pending navigation entry to worry about. However, the old frame entry
325 // must be removed from frame map, and possibly marked complete and deleted.
326 if (frame_it != render_frame_data_use_map_.end()) {
327 DataUseRecorderEntry old_frame_entry = frame_it->second;
328 render_frame_data_use_map_.erase(frame_it);
329 if (old_frame_entry->IsDataUseComplete()) {
330 OnDataUseCompleted(old_frame_entry);
331 data_use_recorders_.erase(old_frame_entry);
332 }
333
334 // Add a new recorder to the render frame map to replace the deleted one.
335 DataUseRecorderEntry entry = data_use_recorders_.insert(
336 data_use_recorders_.end(), ChromeDataUseRecorder());
337 render_frame_data_use_map_.insert(std::make_pair(
338 RenderFrameHostID(render_process_id, render_frame_id), entry));
339 }
340 return;
341 }
342
343 DataUseRecorderEntry entry = navigation_iter->second;
344 pending_navigation_data_use_map_.erase(navigation_iter);
345 entry->set_main_frame_id(
346 RenderFrameHostID(render_process_id, render_frame_id));
347
348 // If the frame has already been deleted then mark this navigation as having
349 // completed its data use.
350 if (frame_it == render_frame_data_use_map_.end()) {
351 if (entry->IsDataUseComplete()) {
352 OnDataUseCompleted(entry);
353 data_use_recorders_.erase(entry);
354 }
355 return;
356 }
357 DataUseRecorderEntry old_frame_entry = frame_it->second;
358 if (is_same_page_navigation) {
359 old_frame_entry->MergeFrom(&(*entry));
360
361 for (auto request : entry->pending_url_requests()) {
362 request->RemoveUserData(DataUseRecorderEntryAsUserData::kUserDataKey);
363 request->SetUserData(DataUseRecorderEntryAsUserData::kUserDataKey,
364 new DataUseRecorderEntryAsUserData(old_frame_entry));
365 old_frame_entry->AddPendingURLRequest(request);
366 }
367
368 entry->RemoveAllPendingURLRequests();
369
370 data_use_recorders_.erase(entry);
371 } else {
372 // Navigation is not same page, so remove old entry from
373 // |render_frame_data_use_map_|, possibly marking it complete.
374 render_frame_data_use_map_.erase(frame_it);
375 if (old_frame_entry->IsDataUseComplete()) {
376 OnDataUseCompleted(old_frame_entry);
377 data_use_recorders_.erase(old_frame_entry);
378 }
379
380 DataUse& data_use = entry->data_use();
381
382 DCHECK(!data_use.url().is_valid() || data_use.url() == gurl)
383 << "is valid: " << data_use.url().is_valid()
384 << "; data_use.url(): " << data_use.url().spec()
385 << "; gurl: " << gurl.spec();
386 if (!data_use.url().is_valid()) {
387 data_use.set_url(gurl);
388 }
389
390 render_frame_data_use_map_.insert(std::make_pair(
391 RenderFrameHostID(render_process_id, render_frame_id), entry));
392 }
165 } 393 }
166 394
167 void ChromeDataUseAscriber::DidRedirectMainFrameNavigation( 395 void ChromeDataUseAscriber::OnDataUseCompleted(DataUseRecorderEntry entry) {
168 GURL gurl, 396 // TODO(ryansturm): Notify observers that data use is complete.
169 int render_process_id,
170 int render_frame_id,
171 void* navigation_handle) {
172 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
173 }
174
175 void ChromeDataUseAscriber::DeletePendingNavigationEntry(
176 content::GlobalRequestID global_request_id) {
177 auto navigation_iter =
178 pending_navigation_data_use_map_.find(global_request_id);
179 // Pending navigation entry will not be found if finish navigation
180 // raced the URLRequest.
181 if (navigation_iter != pending_navigation_data_use_map_.end()) {
182 auto entry = navigation_iter->second;
183 pending_navigation_data_use_map_.erase(navigation_iter);
184 data_use_recorders_.erase(entry);
185 }
186 } 397 }
187 398
188 std::unique_ptr<URLRequestClassifier> 399 std::unique_ptr<URLRequestClassifier>
189 ChromeDataUseAscriber::CreateURLRequestClassifier() const { 400 ChromeDataUseAscriber::CreateURLRequestClassifier() const {
190 return base::MakeUnique<ContentURLRequestClassifier>(); 401 return base::MakeUnique<ContentURLRequestClassifier>();
191 } 402 }
192 403
404 ChromeDataUseAscriber::DataUseRecorderEntry
405 ChromeDataUseAscriber::CreateNewDataUseRecorder(net::URLRequest* request) {
406 DataUseRecorderEntry entry = data_use_recorders_.insert(
RyanSturm 2016/12/01 00:40:46 I think these two inserts (here and above) are sli
Not at Google. Contact bengr 2016/12/01 01:23:39 Done.
407 data_use_recorders_.end(), ChromeDataUseRecorder());
408 if (request) {
409 entry->AddPendingURLRequest(request);
410 request->SetUserData(DataUseRecorderEntryAsUserData::kUserDataKey,
411 new DataUseRecorderEntryAsUserData(entry));
412 }
413 return entry;
414 }
415
193 } // namespace data_use_measurement 416 } // namespace data_use_measurement
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698