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

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

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

Powered by Google App Engine
This is Rietveld 408576698