Chromium Code Reviews| Index: components/rappor/rappor_service.cc |
| diff --git a/components/rappor/rappor_service.cc b/components/rappor/rappor_service.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a390fe1a4aec870bc26b7a7db1fb125de4b35907 |
| --- /dev/null |
| +++ b/components/rappor/rappor_service.cc |
| @@ -0,0 +1,172 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "components/rappor/rappor_service.h" |
| + |
| +#include <cstdlib> |
|
Alexei Svitkine (slow)
2014/01/24 22:09:03
Why is this needed?
Steven Holte
2014/01/24 23:26:58
Removed
|
| + |
| +#include "base/base64.h" |
| +#include "base/hash.h" |
| +#include "base/metrics/field_trial.h" |
| +#include "base/prefs/pref_registry_simple.h" |
| +#include "base/prefs/pref_service.h" |
| +#include "base/rand_util.h" |
| +#include "base/stl_util.h" |
| +#include "components/rappor/proto/rappor_metric.pb.h" |
| +#include "components/rappor/rappor_pref_names.h" |
| +#include "components/variations/variations_associated_data.h" |
| +#include "url/gurl.h" |
| + |
| +namespace { |
| + |
| +// Seconds before the initial log is generated. |
| +const int kInitialLogIntervalSeconds = 15; |
| +// Interval between ongoing logs. |
| +const int kLogIntervalSeconds = 30 * 60; |
| + |
| +const char kMimeType[] = "application/vnd.chrome.rappor"; |
| + |
| +// Constants for the RAPPOR rollout field trial. |
| +const char kRapporRolloutFieldTrialName[] = "RapporRollout"; |
| + |
| +// Constant for the finch parameter name for the server URL |
| +const char kRapporRolloutServerUrlParam[] = "ServerUrl"; |
| + |
| +GURL GetServerUrl() { |
| + return GURL(chrome_variations::GetVariationParamValue( |
| + kRapporRolloutFieldTrialName, |
| + kRapporRolloutServerUrlParam)); |
| +} |
| + |
| +} // namespace |
| + |
| +namespace rappor { |
| + |
| +RapporService::RapporService() {} |
| + |
| +RapporService::~RapporService() {} |
| + |
| +void RapporService::Start(PrefService* pref_service, |
| + net::URLRequestContextGetter* request_context) { |
| + GURL server_url = GetServerUrl(); |
| + if (!server_url.is_valid()) |
| + return; |
| + DCHECK(!uploader_); |
| + GetSecret(pref_service); |
| + uploader_.reset(new LogUploader(server_url, kMimeType, request_context)); |
| + log_rotation_timer_.Start( |
| + FROM_HERE, |
| + base::TimeDelta::FromSeconds(kInitialLogIntervalSeconds), |
| + this, |
| + &RapporService::OnLogInterval); |
| +} |
| + |
| +void RapporService::OnLogInterval() { |
| + DCHECK(uploader_); |
| + RapporReports reports; |
| + LogMetrics(&reports); |
| + if (reports.report_size() > 0) { |
| + std::string log_text; |
| + bool success = reports.SerializeToString(&log_text); |
| + DCHECK(success); |
| + uploader_->QueueLog(log_text); |
| + } |
| + log_rotation_timer_.Start(FROM_HERE, |
| + base::TimeDelta::FromSeconds(kLogIntervalSeconds), |
| + this, |
| + &RapporService::OnLogInterval); |
| +} |
| + |
| +// static |
| +void RapporService::RegisterPrefs(PrefRegistrySimple* registry) { |
| + registry->RegisterStringPref(prefs::kRapporSecret, std::string()); |
| +} |
| + |
| +void RapporService::GetSecret(PrefService* pref_service) { |
| + if (!secret_.empty()) |
| + return; |
| + std::string secret_base64 = |
| + pref_service->GetString(prefs::kRapporSecret); |
| + if (!secret_base64.empty()) { |
| + bool decoded = base::Base64Decode(secret_base64, &secret_); |
| + if (decoded) |
| + return; |
| + // If the preference fails to decode, it must be corrupt, so continue as |
| + // though it didn't exist yet and generate a new one. |
| + } |
| + |
| + secret_ = base::RandBytesAsString(128); |
| + base::Base64Encode(secret_, &secret_base64); |
| + pref_service->SetString(prefs::kRapporSecret, secret_base64); |
| +} |
| + |
| +void RapporService::LogMetric(const RapporMetric& metric, |
| + RapporReports::Report* report) { |
| + report->set_name_hash(base::Hash(metric.parameters()->rappor_name)); |
|
Alexei Svitkine (slow)
2014/01/24 22:09:03
I wouldn't use base::Hash() here - I think that on
Steven Holte
2014/01/24 23:26:58
Good catch! I thought I'd already had this set to
|
| + ByteVector bytes = metric.GetReport(secret_); |
| + std::string byte_string(bytes.begin(), bytes.end()); |
| + report->set_bits(byte_string); |
| +} |
| + |
| +void RapporService::LogMetrics(RapporReports* reports) { |
| + base::AutoLock auto_lock(lock_); |
| + |
| + for (std::map<std::string, RapporMetric*>::iterator it = metrics_map_.begin(); |
| + metrics_map_.end() != it; |
| + ++it) { |
| + const RapporMetric* metric = it->second; |
| + DCHECK_EQ(it->first, metric->parameters()->rappor_name); |
| + RapporReports::Report* report = reports->add_report(); |
| + LogMetric(*metric, report); |
| + } |
| + STLDeleteContainerPairSecondPointers( |
| + metrics_map_.begin(), metrics_map_.end()); |
| + metrics_map_.clear(); |
| +} |
| + |
| +void RapporService::RecordSamples(const RapporParameters& parameters, |
| + const std::vector<std::string>& samples) { |
| + if (!GetServerUrl().is_valid()) |
| + return; |
| + RecordSamplesInternal(parameters, samples); |
| +} |
| + |
| +void RapporService::RecordUrl(const RapporParameters& parameters, |
| + const GURL& url) { |
| + if (!GetServerUrl().is_valid()) |
| + return; |
| + std::vector<std::string> samples; |
| + samples.push_back(url.spec()); |
| + samples.push_back(url.host()); |
| + // TODO(holte): break up host more |
| + samples.push_back(url.query()); |
| + samples.push_back(url.path()); |
| + RecordSamplesInternal(parameters, samples); |
| +} |
| + |
| +void RapporService::RecordSamplesInternal( |
| + const RapporParameters& parameters, |
| + const std::vector<std::string>& samples) { |
| + base::AutoLock auto_lock(lock_); |
| + |
| + RapporMetric* metric = LookupMetric(parameters); |
| + metric->AddSamples(samples); |
| +} |
| + |
| +RapporMetric* RapporService::LookupMetric( |
| + const RapporParameters& parameters) { |
| + std::map<std::string, RapporMetric*>::iterator it = |
| + metrics_map_.find(parameters.rappor_name); |
| + if (metrics_map_.end() != it) { |
| + RapporMetric* metric = it->second; |
| + DCHECK_EQ(parameters.ToString(), metric->parameters()->ToString()); |
| + return metric; |
| + } |
| + |
| + RapporMetric* new_metric = new RapporMetric(parameters); |
| + metrics_map_[parameters.rappor_name] = new_metric; |
| + return new_metric; |
| +} |
| + |
| +} // namespace rappor |