1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/rappor/rappor_service.h"
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/base64.h"
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/metrics/field_trial.h"
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/prefs/pref_registry_simple.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/prefs/pref_service.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/rand_util.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/stl_util.h"
13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/time/time.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/metrics/metrics_hashes.h"
15effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/rappor/log_uploader.h"
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/rappor/proto/rappor_metric.pb.h"
17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/rappor/rappor_metric.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/rappor/rappor_pref_names.h"
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/variations/variations_associated_data.h"
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace rappor {
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace {
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Seconds before the initial log is generated.
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kInitialLogIntervalSeconds = 15;
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Interval between ongoing logs.
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kLogIntervalSeconds = 30 * 60;
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kMimeType[] = "application/vnd.chrome.rappor";
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kRapporDailyEventHistogram[] = "Rappor.DailyEvent.IntervalType";
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Constants for the RAPPOR rollout field trial.
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kRapporRolloutFieldTrialName[] = "RapporRollout";
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Constant for the finch parameter name for the server URL
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kRapporRolloutServerUrlParam[] = "ServerUrl";
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Constant for the finch parameter name for the server URL
416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kRapporRolloutRequireUmaParam[] = "RequireUma";
426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// The rappor server's URL.
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const char kDefaultServerUrl[] = "https://clients4.google.com/rappor";
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)GURL GetServerUrl(bool metrics_enabled) {
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  bool require_uma = variations::GetVariationParamValue(
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      kRapporRolloutFieldTrialName,
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      kRapporRolloutRequireUmaParam) != "False";
506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!metrics_enabled && require_uma)
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return GURL();  // Invalid URL disables Rappor.
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string server_url = variations::GetVariationParamValue(
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kRapporRolloutFieldTrialName,
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      kRapporRolloutServerUrlParam);
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!server_url.empty())
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return GURL(server_url);
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  else
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return GURL(kDefaultServerUrl);
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const RapporParameters kRapporParametersForType[NUM_RAPPOR_TYPES] = {
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // ETLD_PLUS_ONE_RAPPOR_TYPE
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    {128 /* Num cohorts */,
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     16 /* Bloom filter size bytes */,
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     2 /* Bloom filter hash count */,
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     rappor::PROBABILITY_50 /* Fake data probability */,
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     rappor::PROBABILITY_50 /* Fake one probability */,
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     rappor::PROBABILITY_75 /* One coin probability */,
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     rappor::PROBABILITY_25 /* Zero coin probability */},
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciRapporService::RapporService(PrefService* pref_service)
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : pref_service_(pref_service),
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      cohort_(-1),
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      daily_event_(pref_service,
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      prefs::kRapporLastDailySample,
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      kRapporDailyEventHistogram) {
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)RapporService::~RapporService() {
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  STLDeleteValues(&metrics_map_);
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid RapporService::AddDailyObserver(
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<metrics::DailyEvent::Observer> observer) {
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  daily_event_.AddObserver(observer.Pass());
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid RapporService::Start(net::URLRequestContextGetter* request_context,
926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                          bool metrics_enabled) {
936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  const GURL server_url = GetServerUrl(metrics_enabled);
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!server_url.is_valid()) {
956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DVLOG(1) << server_url.spec() << " is invalid. "
966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)             << "RapporService not started.";
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DVLOG(1) << "RapporService started. Reporting to " << server_url.spec();
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!uploader_);
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LoadSecret();
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LoadCohort();
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  uploader_.reset(new LogUploader(server_url, kMimeType, request_context));
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  log_rotation_timer_.Start(
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TimeDelta::FromSeconds(kInitialLogIntervalSeconds),
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      this,
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      &RapporService::OnLogInterval);
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void RapporService::OnLogInterval() {
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(uploader_);
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DVLOG(2) << "RapporService::OnLogInterval";
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  daily_event_.CheckInterval();
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RapporReports reports;
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (ExportMetrics(&reports)) {
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::string log_text;
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool success = reports.SerializeToString(&log_text);
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(success);
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DVLOG(1) << "RapporService sending a report of "
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)             << reports.report_size() << " value(s).";
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uploader_->QueueLog(log_text);
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  log_rotation_timer_.Start(FROM_HERE,
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            base::TimeDelta::FromSeconds(kLogIntervalSeconds),
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            this,
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            &RapporService::OnLogInterval);
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void RapporService::RegisterPrefs(PrefRegistrySimple* registry) {
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  registry->RegisterStringPref(prefs::kRapporSecret, std::string());
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  registry->RegisterIntegerPref(prefs::kRapporCohortDeprecated, -1);
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  registry->RegisterIntegerPref(prefs::kRapporCohortSeed, -1);
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  metrics::DailyEvent::RegisterPref(registry,
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       prefs::kRapporLastDailySample);
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid RapporService::LoadCohort() {
140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(!IsInitialized());
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Ignore and delete old cohort parameter.
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pref_service_->ClearPref(prefs::kRapporCohortDeprecated);
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  cohort_ = pref_service_->GetInteger(prefs::kRapporCohortSeed);
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // If the user is already assigned to a valid cohort, we're done.
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (cohort_ >= 0 && cohort_ < RapporParameters::kMaxCohorts)
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // This is the first time the client has started the service (or their
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // preferences were corrupted).  Randomly assign them to a cohort.
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  cohort_ = base::RandGenerator(RapporParameters::kMaxCohorts);
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DVLOG(2) << "Selected a new Rappor cohort: " << cohort_;
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pref_service_->SetInteger(prefs::kRapporCohortSeed, cohort_);
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid RapporService::LoadSecret() {
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(secret_.empty());
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string secret_base64 = pref_service_->GetString(prefs::kRapporSecret);
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!secret_base64.empty()) {
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool decoded = base::Base64Decode(secret_base64, &secret_);
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (decoded && secret_.size() == HmacByteVectorGenerator::kEntropyInputSize)
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return;
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // If the preference fails to decode, or is the wrong size, it must be
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // corrupt, so continue as though it didn't exist yet and generate a new
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // one.
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DVLOG(2) << "Generated a new Rappor secret.";
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  secret_ = HmacByteVectorGenerator::GenerateEntropyInput();
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::Base64Encode(secret_, &secret_base64);
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pref_service_->SetString(prefs::kRapporSecret, secret_base64);
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool RapporService::ExportMetrics(RapporReports* reports) {
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (metrics_map_.empty())
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_GE(cohort_, 0);
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  reports->set_cohort(cohort_);
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (std::map<std::string, RapporMetric*>::const_iterator it =
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           metrics_map_.begin();
183effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       it != metrics_map_.end();
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++it) {
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const RapporMetric* metric = it->second;
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RapporReports::Report* report = reports->add_report();
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    report->set_name_hash(metrics::HashMetricName(it->first));
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ByteVector bytes = metric->GetReport(secret_);
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    report->set_bits(std::string(bytes.begin(), bytes.end()));
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  STLDeleteValues(&metrics_map_);
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool RapporService::IsInitialized() const {
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return cohort_ >= 0;
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void RapporService::RecordSample(const std::string& metric_name,
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 RapporType type,
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 const std::string& sample) {
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Ignore the sample if the service hasn't started yet.
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!IsInitialized())
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_LT(type, NUM_RAPPOR_TYPES);
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DVLOG(2) << "Recording sample \"" << sample
2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           << "\" for metric \"" << metric_name
2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           << "\" of type: " << type;
209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RecordSampleInternal(metric_name, kRapporParametersForType[type], sample);
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void RapporService::RecordSampleInternal(const std::string& metric_name,
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                         const RapporParameters& parameters,
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                         const std::string& sample) {
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(IsInitialized());
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RapporMetric* metric = LookUpMetric(metric_name, parameters);
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  metric->AddSample(sample);
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)RapporMetric* RapporService::LookUpMetric(const std::string& metric_name,
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                          const RapporParameters& parameters) {
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(IsInitialized());
223effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::map<std::string, RapporMetric*>::const_iterator it =
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      metrics_map_.find(metric_name);
225effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (it != metrics_map_.end()) {
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RapporMetric* metric = it->second;
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK_EQ(parameters.ToString(), metric->parameters().ToString());
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return metric;
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RapporMetric* new_metric = new RapporMetric(metric_name, parameters, cohort_);
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  metrics_map_[metric_name] = new_metric;
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return new_metric;
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace rappor
237