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

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

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

Powered by Google App Engine
This is Rietveld 408576698