OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/metrics/variations/variations_service.h" | 5 #include "chrome/browser/metrics/variations/variations_service.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "base/base64.h" | 9 #include "base/base64.h" |
10 #include "base/build_time.h" | 10 #include "base/build_time.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
13 #include "base/metrics/field_trial.h" | 13 #include "base/metrics/field_trial.h" |
14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
15 #include "base/version.h" | 15 #include "base/version.h" |
16 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
17 #include "chrome/browser/metrics/proto/trials_seed.pb.h" | 17 #include "chrome/browser/metrics/proto/trials_seed.pb.h" |
18 #include "chrome/browser/prefs/pref_service.h" | 18 #include "chrome/browser/prefs/pref_service.h" |
19 #include "chrome/common/chrome_switches.h" | 19 #include "chrome/common/chrome_switches.h" |
20 #include "chrome/common/metrics/variations/variations_util.h" | 20 #include "chrome/common/metrics/variations/variations_util.h" |
21 #include "chrome/common/pref_names.h" | 21 #include "chrome/common/pref_names.h" |
22 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
23 #include "content/public/common/url_fetcher.h" | 23 #include "content/public/common/url_fetcher.h" |
24 #include "googleurl/src/gurl.h" | 24 #include "googleurl/src/gurl.h" |
25 #include "net/base/load_flags.h" | 25 #include "net/base/load_flags.h" |
26 #include "net/base/network_change_notifier.h" | 26 #include "net/base/network_change_notifier.h" |
27 #include "net/http/http_response_headers.h" | 27 #include "net/http/http_response_headers.h" |
28 #include "net/http/http_status_code.h" | |
28 #include "net/http/http_util.h" | 29 #include "net/http/http_util.h" |
29 #include "net/url_request/url_fetcher.h" | 30 #include "net/url_request/url_fetcher.h" |
30 #include "net/url_request/url_request_status.h" | 31 #include "net/url_request/url_request_status.h" |
31 | 32 |
32 namespace chrome_variations { | 33 namespace chrome_variations { |
33 | 34 |
34 namespace { | 35 namespace { |
35 | 36 |
36 // Default server of Variations seed info. | 37 // Default server of Variations seed info. |
37 const char kDefaultVariationsServerURL[] = | 38 const char kDefaultVariationsServerURL[] = |
38 "https://clients4.google.com/chrome-variations/seed"; | 39 "https://clients4.google.com/chrome-variations/seed"; |
39 const int kMaxRetrySeedFetch = 5; | 40 const int kMaxRetrySeedFetch = 5; |
40 | 41 |
41 // Time between seed fetches, in hours. | 42 // Time between seed fetches, in hours. |
42 const int kSeedFetchPeriodHours = 5; | 43 const int kSeedFetchPeriodHours = 5; |
43 | 44 |
45 // TODO(mad): To be moved to NetworkTimeService when available. | |
46 // base::TimeTicks::Now() is documented to have a resolution of | |
47 // ~1-15ms. | |
48 const int64 kTicksResolutionMs = 15; | |
49 | |
50 // For the sources that are supported (HTTP date headers, TLS | |
51 // handshake), the resolution of the server time is 1 second. | |
52 const int64 kServerTimeResolutionMs = 1000; | |
53 | |
44 // Maps Study_Channel enum values to corresponding chrome::VersionInfo::Channel | 54 // Maps Study_Channel enum values to corresponding chrome::VersionInfo::Channel |
45 // enum values. | 55 // enum values. |
46 chrome::VersionInfo::Channel ConvertStudyChannelToVersionChannel( | 56 chrome::VersionInfo::Channel ConvertStudyChannelToVersionChannel( |
47 Study_Channel study_channel) { | 57 Study_Channel study_channel) { |
48 switch (study_channel) { | 58 switch (study_channel) { |
49 case Study_Channel_CANARY: | 59 case Study_Channel_CANARY: |
50 return chrome::VersionInfo::CHANNEL_CANARY; | 60 return chrome::VersionInfo::CHANNEL_CANARY; |
51 case Study_Channel_DEV: | 61 case Study_Channel_DEV: |
52 return chrome::VersionInfo::CHANNEL_DEV; | 62 return chrome::VersionInfo::CHANNEL_DEV; |
53 case Study_Channel_BETA: | 63 case Study_Channel_BETA: |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
180 DCHECK(create_trials_from_seed_called_); | 190 DCHECK(create_trials_from_seed_called_); |
181 | 191 |
182 // Perform the first fetch. | 192 // Perform the first fetch. |
183 FetchVariationsSeed(); | 193 FetchVariationsSeed(); |
184 | 194 |
185 // Repeat this periodically. | 195 // Repeat this periodically. |
186 timer_.Start(FROM_HERE, base::TimeDelta::FromHours(kSeedFetchPeriodHours), | 196 timer_.Start(FROM_HERE, base::TimeDelta::FromHours(kSeedFetchPeriodHours), |
187 this, &VariationsService::FetchVariationsSeed); | 197 this, &VariationsService::FetchVariationsSeed); |
188 } | 198 } |
189 | 199 |
200 bool VariationsService::GetNetworkTime(base::Time* network_time, | |
201 base::TimeDelta* uncertainty) const { | |
202 return network_service_.GetNetworkTime(network_time, uncertainty); | |
203 } | |
204 | |
190 #if defined(OS_WIN) | 205 #if defined(OS_WIN) |
191 void VariationsService::StartGoogleUpdateRegistrySync() { | 206 void VariationsService::StartGoogleUpdateRegistrySync() { |
192 registry_syncer_.RequestRegistrySync(); | 207 registry_syncer_.RequestRegistrySync(); |
193 } | 208 } |
194 #endif | 209 #endif |
195 | 210 |
196 void VariationsService::SetCreateTrialsFromSeedCalledForTesting(bool called) { | 211 void VariationsService::SetCreateTrialsFromSeedCalledForTesting(bool called) { |
197 create_trials_from_seed_called_ = called; | 212 create_trials_from_seed_called_ = called; |
198 } | 213 } |
199 | 214 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
249 DCHECK_EQ(pending_seed_request_.get(), source); | 264 DCHECK_EQ(pending_seed_request_.get(), source); |
250 // The fetcher will be deleted when the request is handled. | 265 // The fetcher will be deleted when the request is handled. |
251 scoped_ptr<const net::URLFetcher> request( | 266 scoped_ptr<const net::URLFetcher> request( |
252 pending_seed_request_.release()); | 267 pending_seed_request_.release()); |
253 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS) { | 268 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS) { |
254 DVLOG(1) << "Variations server request failed."; | 269 DVLOG(1) << "Variations server request failed."; |
255 return; | 270 return; |
256 } | 271 } |
257 | 272 |
258 // Log the response code. | 273 // Log the response code. |
274 const int response_code = request->GetResponseCode(); | |
259 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Variations.SeedFetchResponseCode", | 275 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Variations.SeedFetchResponseCode", |
260 net::HttpUtil::MapStatusCodeForHistogram(request->GetResponseCode()), | 276 net::HttpUtil::MapStatusCodeForHistogram(response_code), |
261 net::HttpUtil::GetStatusCodesForHistogram()); | 277 net::HttpUtil::GetStatusCodesForHistogram()); |
262 | 278 |
263 const base::TimeDelta latency = | 279 const base::TimeDelta latency = |
264 base::TimeTicks::Now() - last_request_started_time_; | 280 base::TimeTicks::Now() - last_request_started_time_; |
265 | 281 |
266 if (request->GetResponseCode() != 200) { | 282 base::Time response_date; |
267 DVLOG(1) << "Variations server request returned non-200 response code: " | 283 if (response_code == net::HTTP_OK || |
268 << request->GetResponseCode(); | 284 response_code == net::HTTP_NOT_MODIFIED) { |
269 if (request->GetResponseCode() == 304) | 285 bool success = request->GetResponseHeaders()->GetDateValue(&response_date); |
286 DCHECK(success || response_date.is_null()); | |
287 | |
288 if (!response_date.is_null()) | |
289 network_service_.SetNetworkTime(response_date, latency); | |
290 } else if (response_code != net::HTTP_OK) { | |
291 DVLOG(1) << "Variations server request returned non-HTTP_OK response code: " | |
292 << response_code; | |
293 if (response_code == net::HTTP_NOT_MODIFIED) | |
270 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchNotModifiedLatency", latency); | 294 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchNotModifiedLatency", latency); |
271 else | 295 else |
272 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchOtherLatency", latency); | 296 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchOtherLatency", latency); |
273 return; | 297 return; |
274 } | 298 } |
275 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchSuccessLatency", latency); | 299 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchSuccessLatency", latency); |
276 | 300 |
277 std::string seed_data; | 301 std::string seed_data; |
278 bool success = request->GetResponseAsString(&seed_data); | 302 bool success = request->GetResponseAsString(&seed_data); |
279 DCHECK(success); | 303 DCHECK(success); |
280 | 304 |
281 base::Time response_date; | |
282 success = request->GetResponseHeaders()->GetDateValue(&response_date); | |
283 DCHECK(success || response_date.is_null()); | |
284 | |
285 StoreSeedData(seed_data, response_date, g_browser_process->local_state()); | 305 StoreSeedData(seed_data, response_date, g_browser_process->local_state()); |
286 } | 306 } |
287 | 307 |
288 void VariationsService::OnResourceRequestsAllowed() { | 308 void VariationsService::OnResourceRequestsAllowed() { |
289 // Note that this only attempts to fetch the seed at most once per period | 309 // Note that this only attempts to fetch the seed at most once per period |
290 // (kSeedFetchPeriodHours). This works because | 310 // (kSeedFetchPeriodHours). This works because |
291 // |resource_request_allowed_notifier_| only calls this method if an | 311 // |resource_request_allowed_notifier_| only calls this method if an |
292 // attempt was made earlier that fails (which implies that the period had | 312 // attempt was made earlier that fails (which implies that the period had |
293 // elapsed). After a successful attempt is made, the notifier will know not | 313 // elapsed). After a successful attempt is made, the notifier will know not |
294 // to call this method again until another failed attempt occurs. | 314 // to call this method again until another failed attempt occurs. |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
558 experiment.name(), | 578 experiment.name(), |
559 variation_id); | 579 variation_id); |
560 } | 580 } |
561 } | 581 } |
562 | 582 |
563 trial->SetForced(); | 583 trial->SetForced(); |
564 if (IsStudyExpired(study, reference_date)) | 584 if (IsStudyExpired(study, reference_date)) |
565 trial->Disable(); | 585 trial->Disable(); |
566 } | 586 } |
567 | 587 |
588 bool VariationsService::NetworkTimeService::GetNetworkTime( | |
589 base::Time* network_time, base::TimeDelta* uncertainty) const { | |
Alexei Svitkine (slow)
2013/02/01 22:18:08
Each param on a separate line.
MAD
2013/02/04 21:07:43
Done.
| |
590 if (network_time_.is_null()) | |
591 return false; | |
592 DCHECK(!network_time_ticks_.is_null()); | |
593 DCHECK(network_time); | |
594 *network_time = network_time_ + (base::TimeTicks::Now() - | |
Alexei Svitkine (slow)
2013/02/01 22:18:08
Nit: No need for ()s.
MAD
2013/02/04 21:07:43
Actually, we get a compile error without them:
er
| |
595 network_time_ticks_); | |
596 if (uncertainty) | |
597 *uncertainty = network_time_uncertainty_; | |
598 return true; | |
599 } | |
600 | |
601 void VariationsService::NetworkTimeService::SetNetworkTime( | |
602 const base::Time& network_time, const base::TimeDelta& latency) { | |
603 #ifndef NDEBUG | |
604 if (!network_time_.is_null()) { | |
Alexei Svitkine (slow)
2013/02/01 22:18:08
Can you make a separate function for this check co
MAD
2013/02/04 21:07:43
Done.
| |
605 // Check that we are tracking time correctly. | |
606 base::Time current_network_time; | |
607 base::TimeDelta uncertainty; | |
608 bool success = GetNetworkTime(¤t_network_time, &uncertainty); | |
609 DCHECK(success); | |
610 // Account for network_time's own innaccuracy. | |
611 uncertainty += | |
612 base::TimeDelta::FromMilliseconds(kServerTimeResolutionMs) + | |
613 latency + 2 * base::TimeDelta::FromMilliseconds(kTicksResolutionMs); | |
614 DCHECK(current_network_time >= network_time - uncertainty); | |
615 DCHECK(current_network_time <= network_time + uncertainty); | |
616 DVLOG(1) << current_network_time.ToInternalValue() << " VS " | |
617 << network_time.ToInternalValue() << ", is within: " | |
618 << uncertainty.ToInternalValue(); | |
619 } | |
620 #endif // ifndef NDEBUG | |
621 // Update network time on every request to limit dependency on ticks lag. | |
622 // TODO(mad): Find a heuristic to avoid augmenting the | |
623 // network_time_uncertainty_ too much by a particularly long latency. | |
624 // Maybe only update when we either improve accuracy or drifted too far | |
625 // from network_time. | |
626 network_time_ = network_time; | |
627 // Estimate that the time was set midway through the latency time. | |
628 network_time_ticks_ = base::TimeTicks::Now() - latency / 2; | |
629 // We can't assume a better time than the resolution of the server time | |
630 // and we involve 4 ticks value, each with their own uncertainty, 1 & 2 | |
631 // are the ones used to compute the latency, 3 is the Now() above and 4 | |
632 // will be the Now() used in GetNetworkTime(). | |
633 network_time_uncertainty_ = | |
634 base::TimeDelta::FromMilliseconds(kServerTimeResolutionMs) + | |
635 latency + 4 * base::TimeDelta::FromMilliseconds(kTicksResolutionMs); | |
636 | |
637 } | |
638 | |
568 } // namespace chrome_variations | 639 } // namespace chrome_variations |
OLD | NEW |