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

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

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

Powered by Google App Engine
This is Rietveld 408576698