Chromium Code Reviews| 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" |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 34 namespace { | 34 namespace { |
| 35 | 35 |
| 36 // Default server of Variations seed info. | 36 // Default server of Variations seed info. |
| 37 const char kDefaultVariationsServerURL[] = | 37 const char kDefaultVariationsServerURL[] = |
| 38 "https://clients4.google.com/chrome-variations/seed"; | 38 "https://clients4.google.com/chrome-variations/seed"; |
| 39 const int kMaxRetrySeedFetch = 5; | 39 const int kMaxRetrySeedFetch = 5; |
| 40 | 40 |
| 41 // Time between seed fetches, in hours. | 41 // Time between seed fetches, in hours. |
| 42 const int kSeedFetchPeriodHours = 5; | 42 const int kSeedFetchPeriodHours = 5; |
| 43 | 43 |
| 44 // TODO(mad): To be moved to NetworkTimeService when available. | |
| 45 // base::TimeTicks::Now() is documented to have a resolution of | |
| 46 // ~1-15ms. | |
| 47 const int64 kTicksResolutionMs = 15; | |
| 48 | |
| 49 // For the sources that are supported (HTTP date headers, TLS | |
| 50 // handshake), the resolution of the server time is 1 second. | |
| 51 const int64 kServerTimeResolutionMs = 1000; | |
| 52 | |
| 44 // Maps Study_Channel enum values to corresponding chrome::VersionInfo::Channel | 53 // Maps Study_Channel enum values to corresponding chrome::VersionInfo::Channel |
| 45 // enum values. | 54 // enum values. |
| 46 chrome::VersionInfo::Channel ConvertStudyChannelToVersionChannel( | 55 chrome::VersionInfo::Channel ConvertStudyChannelToVersionChannel( |
| 47 Study_Channel study_channel) { | 56 Study_Channel study_channel) { |
| 48 switch (study_channel) { | 57 switch (study_channel) { |
| 49 case Study_Channel_CANARY: | 58 case Study_Channel_CANARY: |
| 50 return chrome::VersionInfo::CHANNEL_CANARY; | 59 return chrome::VersionInfo::CHANNEL_CANARY; |
| 51 case Study_Channel_DEV: | 60 case Study_Channel_DEV: |
| 52 return chrome::VersionInfo::CHANNEL_DEV; | 61 return chrome::VersionInfo::CHANNEL_DEV; |
| 53 case Study_Channel_BETA: | 62 case Study_Channel_BETA: |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 DCHECK(create_trials_from_seed_called_); | 189 DCHECK(create_trials_from_seed_called_); |
| 181 | 190 |
| 182 // Perform the first fetch. | 191 // Perform the first fetch. |
| 183 FetchVariationsSeed(); | 192 FetchVariationsSeed(); |
| 184 | 193 |
| 185 // Repeat this periodically. | 194 // Repeat this periodically. |
| 186 timer_.Start(FROM_HERE, base::TimeDelta::FromHours(kSeedFetchPeriodHours), | 195 timer_.Start(FROM_HERE, base::TimeDelta::FromHours(kSeedFetchPeriodHours), |
| 187 this, &VariationsService::FetchVariationsSeed); | 196 this, &VariationsService::FetchVariationsSeed); |
| 188 } | 197 } |
| 189 | 198 |
| 199 bool VariationsService::GetNetworkTime(base::Time* network_time, | |
| 200 base::TimeDelta* uncertainty) const { | |
| 201 if (network_time_.is_null()) | |
| 202 return false; | |
| 203 DCHECK(!network_time_ticks_.is_null()); | |
| 204 DCHECK(network_time); | |
| 205 *network_time = network_time_ + (base::TimeTicks::Now() - | |
| 206 network_time_ticks_); | |
| 207 if (uncertainty) | |
| 208 *uncertainty = network_time_uncertainty_; | |
| 209 return true; | |
| 210 } | |
| 211 | |
| 190 #if defined(OS_WIN) | 212 #if defined(OS_WIN) |
| 191 void VariationsService::StartGoogleUpdateRegistrySync() { | 213 void VariationsService::StartGoogleUpdateRegistrySync() { |
| 192 registry_syncer_.RequestRegistrySync(); | 214 registry_syncer_.RequestRegistrySync(); |
| 193 } | 215 } |
| 194 #endif | 216 #endif |
| 195 | 217 |
| 196 void VariationsService::SetCreateTrialsFromSeedCalledForTesting(bool called) { | 218 void VariationsService::SetCreateTrialsFromSeedCalledForTesting(bool called) { |
| 197 create_trials_from_seed_called_ = called; | 219 create_trials_from_seed_called_ = called; |
| 198 } | 220 } |
| 199 | 221 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 249 DCHECK_EQ(pending_seed_request_.get(), source); | 271 DCHECK_EQ(pending_seed_request_.get(), source); |
| 250 // The fetcher will be deleted when the request is handled. | 272 // The fetcher will be deleted when the request is handled. |
| 251 scoped_ptr<const net::URLFetcher> request( | 273 scoped_ptr<const net::URLFetcher> request( |
| 252 pending_seed_request_.release()); | 274 pending_seed_request_.release()); |
| 253 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS) { | 275 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS) { |
| 254 DVLOG(1) << "Variations server request failed."; | 276 DVLOG(1) << "Variations server request failed."; |
| 255 return; | 277 return; |
| 256 } | 278 } |
| 257 | 279 |
| 258 // Log the response code. | 280 // Log the response code. |
| 281 int response_code = request->GetResponseCode(); | |
|
Alexei Svitkine (slow)
2013/02/01 19:38:55
Nit: const
MAD
2013/02/01 22:01:41
Done.
| |
| 259 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Variations.SeedFetchResponseCode", | 282 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Variations.SeedFetchResponseCode", |
| 260 net::HttpUtil::MapStatusCodeForHistogram(request->GetResponseCode()), | 283 net::HttpUtil::MapStatusCodeForHistogram(response_code), |
| 261 net::HttpUtil::GetStatusCodesForHistogram()); | 284 net::HttpUtil::GetStatusCodesForHistogram()); |
| 262 | 285 |
| 263 const base::TimeDelta latency = | 286 const base::TimeDelta latency = |
| 264 base::TimeTicks::Now() - last_request_started_time_; | 287 base::TimeTicks::Now() - last_request_started_time_; |
| 265 | 288 |
| 266 if (request->GetResponseCode() != 200) { | 289 base::Time response_date; |
| 290 if (response_code == 200 || response_code == 304) { | |
|
Alexei Svitkine (slow)
2013/02/01 19:38:55
Can you change the code to use the constants from
MAD
2013/02/01 22:01:41
Done.
MAD
2013/02/01 22:01:41
Done.
| |
| 291 bool success = request->GetResponseHeaders()->GetDateValue(&response_date); | |
| 292 DCHECK(success || response_date.is_null()); | |
| 293 | |
| 294 if (!response_date.is_null()) { | |
| 295 #ifndef NDEBUG | |
| 296 if (!network_time_.is_null()) { | |
| 297 // Check that we are tracking time correctly. | |
| 298 base::Time current_network_time; | |
| 299 base::TimeDelta uncertainty; | |
| 300 success = GetNetworkTime(¤t_network_time, &uncertainty); | |
| 301 DCHECK(success); | |
| 302 // Account for response_date; s own innaccuracy. | |
| 303 uncertainty += | |
| 304 base::TimeDelta::FromMilliseconds(kServerTimeResolutionMs) + | |
| 305 latency + 2 * base::TimeDelta::FromMilliseconds(kTicksResolutionMs); | |
| 306 DCHECK(current_network_time >= response_date - uncertainty); | |
| 307 DCHECK(current_network_time <= response_date + uncertainty); | |
| 308 DVLOG(1) << current_network_time.ToInternalValue() << " VS " | |
| 309 << response_date.ToInternalValue() << ", is within: " | |
| 310 << uncertainty.ToInternalValue(); | |
| 311 } | |
| 312 #endif // ifndef NDEBUG | |
| 313 // Update network time on every request to limit dependency on ticks lag. | |
| 314 // TODO(mad): Find a heuristic to avoid augmenting the | |
| 315 // network_time_uncertainty_ too much by a particularly long latency. | |
| 316 // Maybe only update when we either improve accuracy or drifted too far | |
| 317 // from response_date. | |
| 318 network_time_ = response_date; | |
| 319 // Estimate that the time was set midway through the latency time. | |
| 320 network_time_ticks_ = base::TimeTicks::Now() - latency / 2; | |
| 321 // We can't assume a better time than the resolution of the server time | |
| 322 // and we involve 4 ticks value, each with their own uncertainty, 1 & 2 | |
| 323 // are the ones used to compute the latency, 3 is the Now() above and 4 | |
| 324 // will be the Now() used in GetNetworkTime(). | |
| 325 network_time_uncertainty_ = | |
| 326 base::TimeDelta::FromMilliseconds(kServerTimeResolutionMs) + | |
| 327 latency + 4 * base::TimeDelta::FromMilliseconds(kTicksResolutionMs); | |
| 328 } // if (!response_date.is_null()) | |
| 329 } else if (response_code != 200) { | |
| 267 DVLOG(1) << "Variations server request returned non-200 response code: " | 330 DVLOG(1) << "Variations server request returned non-200 response code: " |
| 268 << request->GetResponseCode(); | 331 << response_code; |
| 269 if (request->GetResponseCode() == 304) | 332 if (response_code == 304) |
| 270 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchNotModifiedLatency", latency); | 333 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchNotModifiedLatency", latency); |
| 271 else | 334 else |
| 272 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchOtherLatency", latency); | 335 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchOtherLatency", latency); |
| 273 return; | 336 return; |
| 274 } | 337 } |
| 275 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchSuccessLatency", latency); | 338 UMA_HISTOGRAM_MEDIUM_TIMES("Variations.FetchSuccessLatency", latency); |
| 276 | 339 |
| 277 std::string seed_data; | 340 std::string seed_data; |
| 278 bool success = request->GetResponseAsString(&seed_data); | 341 bool success = request->GetResponseAsString(&seed_data); |
| 279 DCHECK(success); | 342 DCHECK(success); |
| 280 | 343 |
| 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()); | 344 StoreSeedData(seed_data, response_date, g_browser_process->local_state()); |
| 286 } | 345 } |
| 287 | 346 |
| 288 void VariationsService::OnResourceRequestsAllowed() { | 347 void VariationsService::OnResourceRequestsAllowed() { |
| 289 // Note that this only attempts to fetch the seed at most once per period | 348 // Note that this only attempts to fetch the seed at most once per period |
| 290 // (kSeedFetchPeriodHours). This works because | 349 // (kSeedFetchPeriodHours). This works because |
| 291 // |resource_request_allowed_notifier_| only calls this method if an | 350 // |resource_request_allowed_notifier_| only calls this method if an |
| 292 // attempt was made earlier that fails (which implies that the period had | 351 // 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 | 352 // elapsed). After a successful attempt is made, the notifier will know not |
| 294 // to call this method again until another failed attempt occurs. | 353 // to call this method again until another failed attempt occurs. |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 559 variation_id); | 618 variation_id); |
| 560 } | 619 } |
| 561 } | 620 } |
| 562 | 621 |
| 563 trial->SetForced(); | 622 trial->SetForced(); |
| 564 if (IsStudyExpired(study, reference_date)) | 623 if (IsStudyExpired(study, reference_date)) |
| 565 trial->Disable(); | 624 trial->Disable(); |
| 566 } | 625 } |
| 567 | 626 |
| 568 } // namespace chrome_variations | 627 } // namespace chrome_variations |
| OLD | NEW |