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

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

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

Powered by Google App Engine
This is Rietveld 408576698