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

Side by Side Diff: components/ukm/ukm_service.cc

Issue 2567263003: Basic UkmService implementation (Closed)
Patch Set: Clang-format Created 3 years, 11 months 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 2017 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/ukm/ukm_service.h"
6
7 #include <utility>
8
9 #include "base/feature_list.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/rand_util.h"
14 #include "base/time/time.h"
15 #include "components/metrics/metrics_log_uploader.h"
16 #include "components/metrics/metrics_service_client.h"
17 #include "components/metrics/proto/ukm/report.pb.h"
18 #include "components/prefs/pref_registry_simple.h"
19 #include "components/prefs/pref_service.h"
20 #include "components/ukm/metrics_reporting_scheduler.h"
21 #include "components/ukm/persisted_logs_metrics_impl.h"
22 #include "components/ukm/ukm_pref_names.h"
23 #include "components/variations/variations_associated_data.h"
24
25 namespace ukm {
26
27 namespace {
28
29 const base::Feature kUkmFeature = {"Ukm", base::FEATURE_DISABLED_BY_DEFAULT};
30
31 const char kMimeType[] = "application/vnd.chrome.ukm";
32
33 // Constants for the UKM rollout field trial.
34 const char kUkmRolloutFieldTrialName[] = "UkmRollout";
35
36 // Constant for the variations parameter name for the server URL
37 const char kUkmRolloutServerUrlParam[] = "ServerUrl";
38
39 // The UKM server's URL.
40 const char kDefaultServerUrl[] = "https://clients4.google.com/ukm";
41
42 // The delay, in seconds, after starting recording before doing expensive
43 // initialization work.
44 const int kInitializationDelaySeconds = 5;
45
46 // The number of UKM logs that will be stored in PersistedLogs before logs
47 // start being dropped.
48 const int kMinPersistedLogs = 8;
49
50 // The number of bytes UKM logs that will be stored in PersistedLogs before
51 // logs start being dropped.
52 // This ensures that a reasonable amount of history will be stored even if there
53 // is a long series of very small logs.
54 const int kMinPersistedBytes = 300000;
55
56 // If an upload fails, and the transmission was over this byte count, then we
57 // will discard the log, and not try to retransmit it. We also don't persist
58 // the log to the prefs for transmission during the next chrome session if this
59 // limit is exceeded.
60 const size_t kMaxLogRetransmitSize = 100 * 1024;
61
62 std::string GetServerUrl() {
63 std::string server_url = variations::GetVariationParamValue(
64 kUkmRolloutFieldTrialName, kUkmRolloutServerUrlParam);
65 if (!server_url.empty())
66 return server_url;
67 return kDefaultServerUrl;
68 }
69
70 uint64_t LoadOrGenerateClientId(PrefService* pref_service) {
71 uint64_t client_id = pref_service->GetInteger(prefs::kUkmClientId);
72 if (!client_id) {
73 // Generate and store a new client id.
74 client_id = base::RandUint64();
75 pref_service->SetInteger(prefs::kUkmClientId, client_id);
76 }
77 return client_id;
78 }
79
80 } // namespace
81
82 UkmService::UkmService(PrefService* pref_service,
83 metrics::MetricsServiceClient* client)
84 : pref_service_(pref_service),
85 client_(client),
86 persisted_logs_(std::unique_ptr<ukm::PersistedLogsMetricsImpl>(
87 new ukm::PersistedLogsMetricsImpl()),
88 pref_service,
89 prefs::kUkmPersistedLogs,
90 NULL,
91 kMinPersistedLogs,
92 kMinPersistedBytes,
93 kMaxLogRetransmitSize),
94 initialize_started_(false),
95 self_ptr_factory_(this) {
96 DCHECK(pref_service_);
97 DCHECK(client_);
98
99 persisted_logs_.DeserializeLogs();
100
101 base::Closure rotate_callback =
102 base::Bind(&UkmService::RotateLog, self_ptr_factory_.GetWeakPtr());
103 // MetricsServiceClient outlives UkmService, and
104 // MetricsReportingScheduler is tied to the lifetime of |this|.
105 const base::Callback<base::TimeDelta(void)>& get_upload_interval_callback =
106 base::Bind(&metrics::MetricsServiceClient::GetStandardUploadInterval,
107 base::Unretained(client_));
108 scheduler_.reset(new ukm::MetricsReportingScheduler(
109 rotate_callback, get_upload_interval_callback));
110 }
111
112 UkmService::~UkmService() {}
113
114 void UkmService::Initialize() {
115 DCHECK(thread_checker_.CalledOnValidThread());
116 DVLOG(1) << "UkmService::Initialize";
117 initialize_started_ = true;
118
119 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
120 FROM_HERE,
121 base::Bind(&UkmService::StartInitTask, self_ptr_factory_.GetWeakPtr()),
122 base::TimeDelta::FromSeconds(kInitializationDelaySeconds));
123 }
124
125 void UkmService::EnableReporting() {
126 DCHECK(thread_checker_.CalledOnValidThread());
127 DVLOG(1) << "UkmService::EnableReporting";
128 if (!base::FeatureList::IsEnabled(kUkmFeature))
129 return;
130 if (!initialize_started_)
131 Initialize();
132 scheduler_->Start();
133 }
134
135 void UkmService::DisableReporting() {
136 DCHECK(thread_checker_.CalledOnValidThread());
137 DVLOG(1) << "UkmService::DisableReporting";
138 scheduler_->UploadCancelled();
139 scheduler_->Stop();
140 }
141
142 // static
143 void UkmService::RegisterPrefs(PrefRegistrySimple* registry) {
144 registry->RegisterIntegerPref(prefs::kUkmClientId, 0);
145 registry->RegisterListPref(prefs::kUkmPersistedLogs);
146 }
147
148 void UkmService::StartInitTask() {
149 DCHECK(thread_checker_.CalledOnValidThread());
150 DVLOG(1) << "UkmService::StartInitTask";
151 client_id_ = LoadOrGenerateClientId(pref_service_);
152 client_->InitializeSystemProfileMetrics(base::Bind(
153 &UkmService::FinishedInitTask, self_ptr_factory_.GetWeakPtr()));
154 }
155
156 void UkmService::FinishedInitTask() {
157 DCHECK(thread_checker_.CalledOnValidThread());
158 DVLOG(1) << "UkmService::FinishedInitTask";
159 scheduler_->InitTaskComplete();
160 }
161
162 void UkmService::RotateLog() {
163 DCHECK(thread_checker_.CalledOnValidThread());
164 DCHECK(!log_upload_in_progress_);
165 DVLOG(1) << "UkmService::RotateLog";
166 if (persisted_logs_.empty()) {
167 BuildAndStoreLog();
168 }
169 StartScheduledUpload();
170 }
171
172 void UkmService::BuildAndStoreLog() {
173 DCHECK(thread_checker_.CalledOnValidThread());
174 DVLOG(1) << "UkmService::BuildAndStoreLog";
175 Report report;
176 report.set_client_id(client_id_);
177 // TODO(holte): Populate system_profile.
178 // TODO(zhenw): Populate sources.
179 std::string serialized_log;
180 report.SerializeToString(&serialized_log);
181 persisted_logs_.StoreLog(serialized_log);
182 }
183
184 void UkmService::StartScheduledUpload() {
185 DCHECK(thread_checker_.CalledOnValidThread());
186 DCHECK(!log_upload_in_progress_);
187 persisted_logs_.StageLog();
188 // TODO(holte): Handle data usage on cellular, etc.
189 if (!log_uploader_) {
190 log_uploader_ = client_->CreateUploader(
191 GetServerUrl(), kMimeType, base::Bind(&UkmService::OnLogUploadComplete,
192 self_ptr_factory_.GetWeakPtr()));
193 }
194 log_upload_in_progress_ = true;
195 log_uploader_->UploadLog(persisted_logs_.staged_log(),
196 persisted_logs_.staged_log_hash());
197 }
198
199 void UkmService::OnLogUploadComplete(int response_code) {
200 DCHECK(thread_checker_.CalledOnValidThread());
201 DCHECK(log_upload_in_progress_);
202 DVLOG(1) << "UkmService::OnLogUploadComplete";
203 log_upload_in_progress_ = false;
204
205 UMA_HISTOGRAM_SPARSE_SLOWLY("UKM.Upload.ResponseCode", response_code);
206
207 bool upload_succeeded = response_code == 200;
208
209 // Provide boolean for error recovery (allow us to ignore response_code).
210 bool discard_log = false;
211 const size_t log_size_bytes = persisted_logs_.staged_log().length();
212 if (upload_succeeded) {
213 UMA_HISTOGRAM_COUNTS_10000("UKM.LogSize.OnSuccess", log_size_bytes / 1024);
214 } else if (log_size_bytes > kMaxLogRetransmitSize) {
215 UMA_HISTOGRAM_COUNTS_1M("UKM.OversizeRejected.LogSize",
216 static_cast<int>(log_size_bytes));
217 discard_log = true;
218 } else if (response_code == 400) {
219 // Bad syntax. Retransmission won't work.
220 discard_log = true;
221 }
222
223 if (upload_succeeded || discard_log) {
224 persisted_logs_.DiscardStagedLog();
225 // Store the updated list to disk now that the removed log is uploaded.
226 persisted_logs_.SerializeLogs();
227 }
228
229 // Error 400 indicates a problem with the log, not with the server, so
230 // don't consider that a sign that the server is in trouble.
231 bool server_is_healthy = upload_succeeded || response_code == 400;
232 scheduler_->UploadFinished(server_is_healthy, !persisted_logs_.empty());
233 }
234
235 } // namespace ukm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698