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

Side by Side Diff: components/data_use_measurement/content/data_use_measurement.cc

Issue 2462983003: Move data use measurement to DataUseNetworkDelegate (Closed)
Patch Set: Rebased and fixed nits Created 4 years, 1 month 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
(Empty)
1 // Copyright 2015 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 "components/data_use_measurement/content/data_use_measurement.h"
6
7 #include "base/metrics/histogram_macros.h"
8 #include "base/metrics/sparse_histogram.h"
9 #include "base/strings/stringprintf.h"
10 #include "build/build_config.h"
11 #include "components/data_use_measurement/core/data_use_user_data.h"
12 #include "content/public/browser/resource_request_info.h"
13 #include "net/base/network_change_notifier.h"
14 #include "net/base/upload_data_stream.h"
15 #include "net/http/http_response_headers.h"
16 #include "net/url_request/url_request.h"
17
18 #if defined(OS_ANDROID)
19 #include "net/android/traffic_stats.h"
20 #endif
21
22 namespace data_use_measurement {
23
24 namespace {
25
26 // Records the occurrence of |sample| in |name| histogram. Conventional UMA
27 // histograms are not used because the |name| is not static.
28 void RecordUMAHistogramCount(const std::string& name, int64_t sample) {
29 base::HistogramBase* histogram_pointer = base::Histogram::FactoryGet(
30 name,
31 1, // Minimum sample size in bytes.
32 1000000, // Maximum sample size in bytes. Should cover most of the
33 // requests by services.
34 50, // Bucket count.
35 base::HistogramBase::kUmaTargetedHistogramFlag);
36 histogram_pointer->Add(sample);
37 }
38
39 // This function increases the value of |sample| bucket in |name| sparse
40 // histogram by |value|. Conventional UMA histograms are not used because |name|
41 // is not static.
42 void IncreaseSparseHistogramByValue(const std::string& name,
43 int64_t sample,
44 int64_t value) {
45 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
46 name, base::HistogramBase::kUmaTargetedHistogramFlag);
47 histogram->AddCount(sample, value);
48 }
49
50 #if defined(OS_ANDROID)
51 void IncrementLatencyHistogramByCount(const std::string& name,
52 const base::TimeDelta& latency,
53 int64_t count) {
54 base::HistogramBase* histogram_pointer = base::Histogram::FactoryTimeGet(
55 name,
56 base::TimeDelta::FromMilliseconds(1), // Minimum sample
57 base::TimeDelta::FromHours(1), // Maximum sample
58 50, // Bucket count.
59 base::HistogramBase::kUmaTargetedHistogramFlag);
60 histogram_pointer->AddCount(latency.InMilliseconds(), count);
61 }
62 #endif
63
64 } // namespace
65
66 DataUseMeasurement::DataUseMeasurement(
67 const metrics::UpdateUsagePrefCallbackType& metrics_data_use_forwarder)
68 : metrics_data_use_forwarder_(metrics_data_use_forwarder)
69 #if defined(OS_ANDROID)
70 ,
71 app_state_(base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES),
72 app_listener_(new base::android::ApplicationStatusListener(
73 base::Bind(&DataUseMeasurement::OnApplicationStateChange,
74 base::Unretained(this)))),
75 rx_bytes_os_(0),
76 tx_bytes_os_(0),
77 bytes_transferred_since_last_traffic_stats_query_(0),
78 no_reads_since_background_(false)
79 #endif
80 {
81 }
82
83 DataUseMeasurement::~DataUseMeasurement(){};
84
85 void DataUseMeasurement::OnBeforeURLRequest(net::URLRequest* request) {
86 DataUseUserData* data_use_user_data = reinterpret_cast<DataUseUserData*>(
87 request->GetUserData(DataUseUserData::kUserDataKey));
88 if (!data_use_user_data) {
89 data_use_user_data = new DataUseUserData(
90 DataUseUserData::ServiceName::NOT_TAGGED, CurrentAppState());
91 request->SetUserData(DataUseUserData::kUserDataKey, data_use_user_data);
92 }
93 }
94
95 void DataUseMeasurement::OnBeforeRedirect(const net::URLRequest& request,
96 const GURL& new_location) {
97 // Recording data use of request on redirects.
98 // TODO(rajendrant): May not be needed when http://crbug/651957 is fixed.
99 UpdateDataUsePrefs(request);
100 }
101
102 void DataUseMeasurement::OnNetworkBytesReceived(const net::URLRequest& request,
103 int64_t bytes_received) {
104 UMA_HISTOGRAM_COUNTS("DataUse.BytesReceived.Delegate", bytes_received);
105 ReportDataUseUMA(request, DOWNSTREAM, bytes_received);
106 #if defined(OS_ANDROID)
107 bytes_transferred_since_last_traffic_stats_query_ += bytes_received;
108 #endif
109 }
110
111 void DataUseMeasurement::OnNetworkBytesSent(const net::URLRequest& request,
112 int64_t bytes_sent) {
113 UMA_HISTOGRAM_COUNTS("DataUse.BytesSent.Delegate", bytes_sent);
114 ReportDataUseUMA(request, UPSTREAM, bytes_sent);
115 #if defined(OS_ANDROID)
116 bytes_transferred_since_last_traffic_stats_query_ += bytes_sent;
117 #endif
118 }
119
120 void DataUseMeasurement::OnCompleted(const net::URLRequest& request,
121 bool started) {
122 // TODO(amohammadkhan): Verify that there is no double recording in data use
123 // of redirected requests.
124 UpdateDataUsePrefs(request);
125 #if defined(OS_ANDROID)
126 MaybeRecordNetworkBytesOS();
127 #endif
128 }
129
130 void DataUseMeasurement::ReportDataUseUMA(const net::URLRequest& request,
131 TrafficDirection dir,
132 int64_t bytes) {
133 bool is_user_traffic = IsUserInitiatedRequest(request);
134 bool is_connection_cellular =
135 net::NetworkChangeNotifier::IsConnectionCellular(
136 net::NetworkChangeNotifier::GetConnectionType());
137
138 DataUseUserData* attached_service_data = static_cast<DataUseUserData*>(
139 request.GetUserData(DataUseUserData::kUserDataKey));
140 DataUseUserData::ServiceName service_name = DataUseUserData::NOT_TAGGED;
141 DataUseUserData::AppState old_app_state = DataUseUserData::FOREGROUND;
142 DataUseUserData::AppState new_app_state = DataUseUserData::UNKNOWN;
143
144 if (attached_service_data) {
145 service_name = attached_service_data->service_name();
146 old_app_state = attached_service_data->app_state();
147 }
148 if (old_app_state == CurrentAppState())
149 new_app_state = old_app_state;
150
151 if (attached_service_data && old_app_state != new_app_state)
152 attached_service_data->set_app_state(CurrentAppState());
153
154 RecordUMAHistogramCount(
155 GetHistogramName(is_user_traffic ? "DataUse.TrafficSize.User"
156 : "DataUse.TrafficSize.System",
157 dir, new_app_state, is_connection_cellular),
158 bytes);
159
160 if (!is_user_traffic) {
161 ReportDataUsageServices(service_name, dir, new_app_state,
162 is_connection_cellular, bytes);
163 }
164 #if defined(OS_ANDROID)
165 if (dir == DOWNSTREAM && CurrentAppState() == DataUseUserData::BACKGROUND) {
166 DCHECK(!last_app_background_time_.is_null());
167
168 const base::TimeDelta time_since_background =
169 base::TimeTicks::Now() - last_app_background_time_;
170 IncrementLatencyHistogramByCount(
171 is_user_traffic ? "DataUse.BackgroundToDataRecievedPerByte.User"
172 : "DataUse.BackgroundToDataRecievedPerByte.System",
173 time_since_background, bytes);
174 if (no_reads_since_background_) {
175 no_reads_since_background_ = false;
176 IncrementLatencyHistogramByCount(
177 is_user_traffic ? "DataUse.BackgroundToFirstDownstream.User"
178 : "DataUse.BackgroundToFirstDownstream.System",
179 time_since_background, 1);
180 }
181 }
182 #endif
183 }
184
185 void DataUseMeasurement::UpdateDataUsePrefs(
186 const net::URLRequest& request) const {
187 bool is_connection_cellular =
188 net::NetworkChangeNotifier::IsConnectionCellular(
189 net::NetworkChangeNotifier::GetConnectionType());
190
191 DataUseUserData* attached_service_data = static_cast<DataUseUserData*>(
192 request.GetUserData(DataUseUserData::kUserDataKey));
193 DataUseUserData::ServiceName service_name =
194 attached_service_data ? attached_service_data->service_name()
195 : DataUseUserData::NOT_TAGGED;
196
197 // Update data use prefs for cellular connections.
198 if (!metrics_data_use_forwarder_.is_null()) {
199 metrics_data_use_forwarder_.Run(
200 DataUseUserData::GetServiceNameAsString(service_name),
201 request.GetTotalSentBytes() + request.GetTotalReceivedBytes(),
202 is_connection_cellular);
203 }
204 }
205
206 // static
207 bool DataUseMeasurement::IsUserInitiatedRequest(
208 const net::URLRequest& request) {
209 // Having ResourceRequestInfo in the URL request is a sign that the request is
210 // for a web content from user. For now we could add a condition to check
211 // ProcessType in info is content::PROCESS_TYPE_RENDERER, but it won't be
212 // compatible with upcoming PlzNavigate architecture. So just existence of
213 // ResourceRequestInfo is verified, and the current check should be compatible
214 // with upcoming changes in PlzNavigate.
215 // TODO(rajendrant): Verify this condition for different use cases. See
216 // crbug.com/626063.
217 return content::ResourceRequestInfo::ForRequest(&request) != nullptr;
218 }
219
220 #if defined(OS_ANDROID)
221 void DataUseMeasurement::OnApplicationStateChangeForTesting(
222 base::android::ApplicationState application_state) {
223 OnApplicationStateChange(application_state);
224 }
225 #endif
226
227 DataUseUserData::AppState DataUseMeasurement::CurrentAppState() const {
228 #if defined(OS_ANDROID)
229 if (app_state_ != base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES)
230 return DataUseUserData::BACKGROUND;
231 #endif
232 // If the OS is not Android, all the requests are considered Foreground.
233 return DataUseUserData::FOREGROUND;
234 }
235
236 std::string DataUseMeasurement::GetHistogramName(
237 const char* prefix,
238 TrafficDirection dir,
239 DataUseUserData::AppState app_state,
240 bool is_connection_cellular) const {
241 return base::StringPrintf(
242 "%s.%s.%s.%s", prefix, dir == UPSTREAM ? "Upstream" : "Downstream",
243 app_state == DataUseUserData::UNKNOWN
244 ? "Unknown"
245 : (app_state == DataUseUserData::FOREGROUND ? "Foreground"
246 : "Background"),
247 is_connection_cellular ? "Cellular" : "NotCellular");
248 }
249
250 #if defined(OS_ANDROID)
251 void DataUseMeasurement::OnApplicationStateChange(
252 base::android::ApplicationState application_state) {
253 app_state_ = application_state;
254 if (app_state_ != base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
255 last_app_background_time_ = base::TimeTicks::Now();
256 no_reads_since_background_ = true;
257 MaybeRecordNetworkBytesOS();
258 } else {
259 last_app_background_time_ = base::TimeTicks();
260 }
261 }
262
263 void DataUseMeasurement::MaybeRecordNetworkBytesOS() {
264 // Minimum number of bytes that should be reported by the network delegate
265 // before Android's TrafficStats API is queried (if Chrome is not in
266 // background). This reduces the overhead of repeatedly calling the API.
267 static const int64_t kMinDelegateBytes = 25000;
268
269 if (bytes_transferred_since_last_traffic_stats_query_ < kMinDelegateBytes &&
270 CurrentAppState() == DataUseUserData::FOREGROUND) {
271 return;
272 }
273 bytes_transferred_since_last_traffic_stats_query_ = 0;
274 int64_t bytes = 0;
275 // Query Android traffic stats directly instead of registering with the
276 // DataUseAggregator since the latter does not provide notifications for
277 // the incognito traffic.
278 if (net::android::traffic_stats::GetCurrentUidRxBytes(&bytes)) {
279 if (rx_bytes_os_ != 0) {
280 DCHECK_GE(bytes, rx_bytes_os_);
281 UMA_HISTOGRAM_COUNTS("DataUse.BytesReceived.OS", bytes - rx_bytes_os_);
282 }
283 rx_bytes_os_ = bytes;
284 }
285
286 if (net::android::traffic_stats::GetCurrentUidTxBytes(&bytes)) {
287 if (tx_bytes_os_ != 0) {
288 DCHECK_GE(bytes, tx_bytes_os_);
289 UMA_HISTOGRAM_COUNTS("DataUse.BytesSent.OS", bytes - tx_bytes_os_);
290 }
291 tx_bytes_os_ = bytes;
292 }
293 }
294 #endif
295
296 void DataUseMeasurement::ReportDataUsageServices(
297 DataUseUserData::ServiceName service,
298 TrafficDirection dir,
299 DataUseUserData::AppState app_state,
300 bool is_connection_cellular,
301 int64_t message_size) const {
302 RecordUMAHistogramCount(
303 "DataUse.MessageSize." + DataUseUserData::GetServiceNameAsString(service),
304 message_size);
305 if (message_size > 0) {
306 IncreaseSparseHistogramByValue(
307 GetHistogramName("DataUse.MessageSize.AllServices", dir, app_state,
308 is_connection_cellular),
309 service, message_size);
310 }
311 }
312
313 } // namespace data_use_measurement
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698