1 //
2 // Copyright (C) 2014 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "update_engine/metrics.h"
18
19 #include <string>
20
21 #include <base/logging.h>
22 #include <metrics/metrics_library.h>
23
24 #include "update_engine/common/clock_interface.h"
25 #include "update_engine/common/constants.h"
26 #include "update_engine/common/prefs_interface.h"
27 #include "update_engine/common/utils.h"
28 #include "update_engine/metrics_utils.h"
29 #include "update_engine/system_state.h"
30
31 using std::string;
32
33 namespace chromeos_update_engine {
34
35 namespace metrics {
36
37 // UpdateEngine.Daily.* metrics.
38 const char kMetricDailyOSAgeDays[] = "UpdateEngine.Daily.OSAgeDays";
39
40 // UpdateEngine.Check.* metrics.
41 const char kMetricCheckDownloadErrorCode[] =
42 "UpdateEngine.Check.DownloadErrorCode";
43 const char kMetricCheckReaction[] = "UpdateEngine.Check.Reaction";
44 const char kMetricCheckResult[] = "UpdateEngine.Check.Result";
45 const char kMetricCheckTimeSinceLastCheckMinutes[] =
46 "UpdateEngine.Check.TimeSinceLastCheckMinutes";
47 const char kMetricCheckTimeSinceLastCheckUptimeMinutes[] =
48 "UpdateEngine.Check.TimeSinceLastCheckUptimeMinutes";
49
50 // UpdateEngine.Attempt.* metrics.
51 const char kMetricAttemptNumber[] = "UpdateEngine.Attempt.Number";
52 const char kMetricAttemptPayloadType[] =
53 "UpdateEngine.Attempt.PayloadType";
54 const char kMetricAttemptPayloadSizeMiB[] =
55 "UpdateEngine.Attempt.PayloadSizeMiB";
56 const char kMetricAttemptConnectionType[] =
57 "UpdateEngine.Attempt.ConnectionType";
58 const char kMetricAttemptDurationMinutes[] =
59 "UpdateEngine.Attempt.DurationMinutes";
60 const char kMetricAttemptDurationUptimeMinutes[] =
61 "UpdateEngine.Attempt.DurationUptimeMinutes";
62 const char kMetricAttemptTimeSinceLastAttemptMinutes[] =
63 "UpdateEngine.Attempt.TimeSinceLastAttemptMinutes";
64 const char kMetricAttemptTimeSinceLastAttemptUptimeMinutes[] =
65 "UpdateEngine.Attempt.TimeSinceLastAttemptUptimeMinutes";
66 const char kMetricAttemptPayloadBytesDownloadedMiB[] =
67 "UpdateEngine.Attempt.PayloadBytesDownloadedMiB";
68 const char kMetricAttemptPayloadDownloadSpeedKBps[] =
69 "UpdateEngine.Attempt.PayloadDownloadSpeedKBps";
70 const char kMetricAttemptDownloadSource[] =
71 "UpdateEngine.Attempt.DownloadSource";
72 const char kMetricAttemptResult[] =
73 "UpdateEngine.Attempt.Result";
74 const char kMetricAttemptInternalErrorCode[] =
75 "UpdateEngine.Attempt.InternalErrorCode";
76 const char kMetricAttemptDownloadErrorCode[] =
77 "UpdateEngine.Attempt.DownloadErrorCode";
78
79 // UpdateEngine.SuccessfulUpdate.* metrics.
80 const char kMetricSuccessfulUpdateAttemptCount[] =
81 "UpdateEngine.SuccessfulUpdate.AttemptCount";
82 const char kMetricSuccessfulUpdateBytesDownloadedMiB[] =
83 "UpdateEngine.SuccessfulUpdate.BytesDownloadedMiB";
84 const char kMetricSuccessfulUpdateDownloadOverheadPercentage[] =
85 "UpdateEngine.SuccessfulUpdate.DownloadOverheadPercentage";
86 const char kMetricSuccessfulUpdateDownloadSourcesUsed[] =
87 "UpdateEngine.SuccessfulUpdate.DownloadSourcesUsed";
88 const char kMetricSuccessfulUpdatePayloadType[] =
89 "UpdateEngine.SuccessfulUpdate.PayloadType";
90 const char kMetricSuccessfulUpdatePayloadSizeMiB[] =
91 "UpdateEngine.SuccessfulUpdate.PayloadSizeMiB";
92 const char kMetricSuccessfulUpdateRebootCount[] =
93 "UpdateEngine.SuccessfulUpdate.RebootCount";
94 const char kMetricSuccessfulUpdateTotalDurationMinutes[] =
95 "UpdateEngine.SuccessfulUpdate.TotalDurationMinutes";
96 const char kMetricSuccessfulUpdateUpdatesAbandonedCount[] =
97 "UpdateEngine.SuccessfulUpdate.UpdatesAbandonedCount";
98 const char kMetricSuccessfulUpdateUrlSwitchCount[] =
99 "UpdateEngine.SuccessfulUpdate.UrlSwitchCount";
100
101 // UpdateEngine.Rollback.* metric.
102 const char kMetricRollbackResult[] = "UpdateEngine.Rollback.Result";
103
104 // UpdateEngine.CertificateCheck.* metrics.
105 const char kMetricCertificateCheckUpdateCheck[] =
106 "UpdateEngine.CertificateCheck.UpdateCheck";
107 const char kMetricCertificateCheckDownload[] =
108 "UpdateEngine.CertificateCheck.Download";
109
110 // UpdateEngine.* metrics.
111 const char kMetricFailedUpdateCount[] = "UpdateEngine.FailedUpdateCount";
112 const char kMetricInstallDateProvisioningSource[] =
113 "UpdateEngine.InstallDateProvisioningSource";
114 const char kMetricTimeToRebootMinutes[] =
115 "UpdateEngine.TimeToRebootMinutes";
116
ReportDailyMetrics(SystemState * system_state,base::TimeDelta os_age)117 void ReportDailyMetrics(SystemState *system_state,
118 base::TimeDelta os_age) {
119 string metric = metrics::kMetricDailyOSAgeDays;
120 LOG(INFO) << "Uploading " << utils::FormatTimeDelta(os_age)
121 << " for metric " << metric;
122 system_state->metrics_lib()->SendToUMA(
123 metric,
124 static_cast<int>(os_age.InDays()),
125 0, // min: 0 days
126 6*30, // max: 6 months (approx)
127 50); // num_buckets
128 }
129
ReportUpdateCheckMetrics(SystemState * system_state,CheckResult result,CheckReaction reaction,DownloadErrorCode download_error_code)130 void ReportUpdateCheckMetrics(SystemState *system_state,
131 CheckResult result,
132 CheckReaction reaction,
133 DownloadErrorCode download_error_code) {
134 string metric;
135 int value;
136 int max_value;
137
138 if (result != metrics::CheckResult::kUnset) {
139 metric = metrics::kMetricCheckResult;
140 value = static_cast<int>(result);
141 max_value = static_cast<int>(metrics::CheckResult::kNumConstants) - 1;
142 LOG(INFO) << "Sending " << value << " for metric " << metric << " (enum)";
143 system_state->metrics_lib()->SendEnumToUMA(metric, value, max_value);
144 }
145 if (reaction != metrics::CheckReaction::kUnset) {
146 metric = metrics::kMetricCheckReaction;
147 value = static_cast<int>(reaction);
148 max_value = static_cast<int>(metrics::CheckReaction::kNumConstants) - 1;
149 LOG(INFO) << "Sending " << value << " for metric " << metric << " (enum)";
150 system_state->metrics_lib()->SendEnumToUMA(metric, value, max_value);
151 }
152 if (download_error_code != metrics::DownloadErrorCode::kUnset) {
153 metric = metrics::kMetricCheckDownloadErrorCode;
154 value = static_cast<int>(download_error_code);
155 LOG(INFO) << "Sending " << value << " for metric " << metric << " (sparse)";
156 system_state->metrics_lib()->SendSparseToUMA(metric, value);
157 }
158
159 base::TimeDelta time_since_last;
160 if (metrics_utils::WallclockDurationHelper(
161 system_state,
162 kPrefsMetricsCheckLastReportingTime,
163 &time_since_last)) {
164 metric = kMetricCheckTimeSinceLastCheckMinutes;
165 LOG(INFO) << "Sending " << utils::FormatTimeDelta(time_since_last)
166 << " for metric " << metric;
167 system_state->metrics_lib()->SendToUMA(
168 metric,
169 time_since_last.InMinutes(),
170 0, // min: 0 min
171 30*24*60, // max: 30 days
172 50); // num_buckets
173 }
174
175 base::TimeDelta uptime_since_last;
176 static int64_t uptime_since_last_storage = 0;
177 if (metrics_utils::MonotonicDurationHelper(system_state,
178 &uptime_since_last_storage,
179 &uptime_since_last)) {
180 metric = kMetricCheckTimeSinceLastCheckUptimeMinutes;
181 LOG(INFO) << "Sending " << utils::FormatTimeDelta(uptime_since_last)
182 << " for metric " << metric;
183 system_state->metrics_lib()->SendToUMA(
184 metric,
185 uptime_since_last.InMinutes(),
186 0, // min: 0 min
187 30*24*60, // max: 30 days
188 50); // num_buckets
189 }
190 }
191
ReportAbnormallyTerminatedUpdateAttemptMetrics(SystemState * system_state)192 void ReportAbnormallyTerminatedUpdateAttemptMetrics(
193 SystemState *system_state) {
194
195 string metric = metrics::kMetricAttemptResult;
196 AttemptResult attempt_result = AttemptResult::kAbnormalTermination;
197
198 LOG(INFO) << "Uploading " << static_cast<int>(attempt_result)
199 << " for metric " << metric;
200 system_state->metrics_lib()->SendEnumToUMA(
201 metric,
202 static_cast<int>(attempt_result),
203 static_cast<int>(AttemptResult::kNumConstants));
204 }
205
ReportUpdateAttemptMetrics(SystemState * system_state,int attempt_number,PayloadType payload_type,base::TimeDelta duration,base::TimeDelta duration_uptime,int64_t payload_size,int64_t payload_bytes_downloaded,int64_t payload_download_speed_bps,DownloadSource download_source,AttemptResult attempt_result,ErrorCode internal_error_code,DownloadErrorCode payload_download_error_code,ConnectionType connection_type)206 void ReportUpdateAttemptMetrics(
207 SystemState *system_state,
208 int attempt_number,
209 PayloadType payload_type,
210 base::TimeDelta duration,
211 base::TimeDelta duration_uptime,
212 int64_t payload_size,
213 int64_t payload_bytes_downloaded,
214 int64_t payload_download_speed_bps,
215 DownloadSource download_source,
216 AttemptResult attempt_result,
217 ErrorCode internal_error_code,
218 DownloadErrorCode payload_download_error_code,
219 ConnectionType connection_type) {
220 string metric;
221
222 metric = metrics::kMetricAttemptNumber;
223 LOG(INFO) << "Uploading " << attempt_number << " for metric " << metric;
224 system_state->metrics_lib()->SendToUMA(metric,
225 attempt_number,
226 0, // min: 0 attempts
227 49, // max: 49 attempts
228 50); // num_buckets
229
230 metric = metrics::kMetricAttemptPayloadType;
231 LOG(INFO) << "Uploading " << utils::ToString(payload_type)
232 << " for metric " << metric;
233 system_state->metrics_lib()->SendEnumToUMA(metric,
234 payload_type,
235 kNumPayloadTypes);
236
237 metric = metrics::kMetricAttemptDurationMinutes;
238 LOG(INFO) << "Uploading " << utils::FormatTimeDelta(duration)
239 << " for metric " << metric;
240 system_state->metrics_lib()->SendToUMA(metric,
241 duration.InMinutes(),
242 0, // min: 0 min
243 10*24*60, // max: 10 days
244 50); // num_buckets
245
246 metric = metrics::kMetricAttemptDurationUptimeMinutes;
247 LOG(INFO) << "Uploading " << utils::FormatTimeDelta(duration_uptime)
248 << " for metric " << metric;
249 system_state->metrics_lib()->SendToUMA(metric,
250 duration_uptime.InMinutes(),
251 0, // min: 0 min
252 10*24*60, // max: 10 days
253 50); // num_buckets
254
255 metric = metrics::kMetricAttemptPayloadSizeMiB;
256 int64_t payload_size_mib = payload_size / kNumBytesInOneMiB;
257 LOG(INFO) << "Uploading " << payload_size_mib << " for metric " << metric;
258 system_state->metrics_lib()->SendToUMA(metric,
259 payload_size_mib,
260 0, // min: 0 MiB
261 1024, // max: 1024 MiB = 1 GiB
262 50); // num_buckets
263
264 metric = metrics::kMetricAttemptPayloadBytesDownloadedMiB;
265 int64_t payload_bytes_downloaded_mib =
266 payload_bytes_downloaded / kNumBytesInOneMiB;
267 LOG(INFO) << "Uploading " << payload_bytes_downloaded_mib
268 << " for metric " << metric;
269 system_state->metrics_lib()->SendToUMA(metric,
270 payload_bytes_downloaded_mib,
271 0, // min: 0 MiB
272 1024, // max: 1024 MiB = 1 GiB
273 50); // num_buckets
274
275 metric = metrics::kMetricAttemptPayloadDownloadSpeedKBps;
276 int64_t payload_download_speed_kbps = payload_download_speed_bps / 1000;
277 LOG(INFO) << "Uploading " << payload_download_speed_kbps
278 << " for metric " << metric;
279 system_state->metrics_lib()->SendToUMA(metric,
280 payload_download_speed_kbps,
281 0, // min: 0 kB/s
282 10*1000, // max: 10000 kB/s = 10 MB/s
283 50); // num_buckets
284
285 metric = metrics::kMetricAttemptDownloadSource;
286 LOG(INFO) << "Uploading " << download_source
287 << " for metric " << metric;
288 system_state->metrics_lib()->SendEnumToUMA(metric,
289 download_source,
290 kNumDownloadSources);
291
292 metric = metrics::kMetricAttemptResult;
293 LOG(INFO) << "Uploading " << static_cast<int>(attempt_result)
294 << " for metric " << metric;
295 system_state->metrics_lib()->SendEnumToUMA(
296 metric,
297 static_cast<int>(attempt_result),
298 static_cast<int>(AttemptResult::kNumConstants));
299
300 if (internal_error_code != ErrorCode::kSuccess) {
301 metric = metrics::kMetricAttemptInternalErrorCode;
302 LOG(INFO) << "Uploading " << internal_error_code
303 << " for metric " << metric;
304 system_state->metrics_lib()->SendEnumToUMA(
305 metric,
306 static_cast<int>(internal_error_code),
307 static_cast<int>(ErrorCode::kUmaReportedMax));
308 }
309
310 if (payload_download_error_code != DownloadErrorCode::kUnset) {
311 metric = metrics::kMetricAttemptDownloadErrorCode;
312 LOG(INFO) << "Uploading " << static_cast<int>(payload_download_error_code)
313 << " for metric " << metric << " (sparse)";
314 system_state->metrics_lib()->SendSparseToUMA(
315 metric,
316 static_cast<int>(payload_download_error_code));
317 }
318
319 base::TimeDelta time_since_last;
320 if (metrics_utils::WallclockDurationHelper(
321 system_state,
322 kPrefsMetricsAttemptLastReportingTime,
323 &time_since_last)) {
324 metric = kMetricAttemptTimeSinceLastAttemptMinutes;
325 LOG(INFO) << "Sending " << utils::FormatTimeDelta(time_since_last)
326 << " for metric " << metric;
327 system_state->metrics_lib()->SendToUMA(
328 metric,
329 time_since_last.InMinutes(),
330 0, // min: 0 min
331 30*24*60, // max: 30 days
332 50); // num_buckets
333 }
334
335 static int64_t uptime_since_last_storage = 0;
336 base::TimeDelta uptime_since_last;
337 if (metrics_utils::MonotonicDurationHelper(system_state,
338 &uptime_since_last_storage,
339 &uptime_since_last)) {
340 metric = kMetricAttemptTimeSinceLastAttemptUptimeMinutes;
341 LOG(INFO) << "Sending " << utils::FormatTimeDelta(uptime_since_last)
342 << " for metric " << metric;
343 system_state->metrics_lib()->SendToUMA(
344 metric,
345 uptime_since_last.InMinutes(),
346 0, // min: 0 min
347 30*24*60, // max: 30 days
348 50); // num_buckets
349 }
350
351 metric = metrics::kMetricAttemptConnectionType;
352 LOG(INFO) << "Uploading " << static_cast<int>(connection_type)
353 << " for metric " << metric;
354 system_state->metrics_lib()->SendEnumToUMA(
355 metric,
356 static_cast<int>(connection_type),
357 static_cast<int>(ConnectionType::kNumConstants));
358 }
359
360
ReportSuccessfulUpdateMetrics(SystemState * system_state,int attempt_count,int updates_abandoned_count,PayloadType payload_type,int64_t payload_size,int64_t num_bytes_downloaded[kNumDownloadSources],int download_overhead_percentage,base::TimeDelta total_duration,int reboot_count,int url_switch_count)361 void ReportSuccessfulUpdateMetrics(
362 SystemState *system_state,
363 int attempt_count,
364 int updates_abandoned_count,
365 PayloadType payload_type,
366 int64_t payload_size,
367 int64_t num_bytes_downloaded[kNumDownloadSources],
368 int download_overhead_percentage,
369 base::TimeDelta total_duration,
370 int reboot_count,
371 int url_switch_count) {
372 string metric;
373 int64_t mbs;
374
375 metric = kMetricSuccessfulUpdatePayloadSizeMiB;
376 mbs = payload_size / kNumBytesInOneMiB;
377 LOG(INFO) << "Uploading " << mbs << " (MiBs) for metric " << metric;
378 system_state->metrics_lib()->SendToUMA(metric,
379 mbs,
380 0, // min: 0 MiB
381 1024, // max: 1024 MiB = 1 GiB
382 50); // num_buckets
383
384 int64_t total_bytes = 0;
385 int download_sources_used = 0;
386 for (int i = 0; i < kNumDownloadSources + 1; i++) {
387 DownloadSource source = static_cast<DownloadSource>(i);
388
389 // Only consider this download source (and send byte counts) as
390 // having been used if we downloaded a non-trivial amount of bytes
391 // (e.g. at least 1 MiB) that contributed to the
392 // update. Otherwise we're going to end up with a lot of zero-byte
393 // events in the histogram.
394
395 metric = metrics::kMetricSuccessfulUpdateBytesDownloadedMiB;
396 if (i < kNumDownloadSources) {
397 metric += utils::ToString(source);
398 mbs = num_bytes_downloaded[i] / kNumBytesInOneMiB;
399 total_bytes += num_bytes_downloaded[i];
400 if (mbs > 0)
401 download_sources_used |= (1 << i);
402 } else {
403 mbs = total_bytes / kNumBytesInOneMiB;
404 }
405
406 if (mbs > 0) {
407 LOG(INFO) << "Uploading " << mbs << " (MiBs) for metric " << metric;
408 system_state->metrics_lib()->SendToUMA(metric,
409 mbs,
410 0, // min: 0 MiB
411 1024, // max: 1024 MiB = 1 GiB
412 50); // num_buckets
413 }
414 }
415
416 metric = metrics::kMetricSuccessfulUpdateDownloadSourcesUsed;
417 LOG(INFO) << "Uploading 0x" << std::hex << download_sources_used
418 << " (bit flags) for metric " << metric;
419 system_state->metrics_lib()->SendToUMA(
420 metric,
421 download_sources_used,
422 0, // min
423 (1 << kNumDownloadSources) - 1, // max
424 1 << kNumDownloadSources); // num_buckets
425
426 metric = metrics::kMetricSuccessfulUpdateDownloadOverheadPercentage;
427 LOG(INFO) << "Uploading " << download_overhead_percentage
428 << "% for metric " << metric;
429 system_state->metrics_lib()->SendToUMA(metric,
430 download_overhead_percentage,
431 0, // min: 0% overhead
432 1000, // max: 1000% overhead
433 50); // num_buckets
434
435 metric = metrics::kMetricSuccessfulUpdateUrlSwitchCount;
436 LOG(INFO) << "Uploading " << url_switch_count
437 << " (count) for metric " << metric;
438 system_state->metrics_lib()->SendToUMA(metric,
439 url_switch_count,
440 0, // min: 0 URL switches
441 49, // max: 49 URL switches
442 50); // num_buckets
443
444 metric = metrics::kMetricSuccessfulUpdateTotalDurationMinutes;
445 LOG(INFO) << "Uploading " << utils::FormatTimeDelta(total_duration)
446 << " for metric " << metric;
447 system_state->metrics_lib()->SendToUMA(
448 metric,
449 static_cast<int>(total_duration.InMinutes()),
450 0, // min: 0 min
451 365*24*60, // max: 365 days ~= 1 year
452 50); // num_buckets
453
454 metric = metrics::kMetricSuccessfulUpdateRebootCount;
455 LOG(INFO) << "Uploading reboot count of " << reboot_count << " for metric "
456 << metric;
457 system_state->metrics_lib()->SendToUMA(metric,
458 reboot_count,
459 0, // min: 0 reboots
460 49, // max: 49 reboots
461 50); // num_buckets
462
463 metric = metrics::kMetricSuccessfulUpdatePayloadType;
464 system_state->metrics_lib()->SendEnumToUMA(metric,
465 payload_type,
466 kNumPayloadTypes);
467 LOG(INFO) << "Uploading " << utils::ToString(payload_type)
468 << " for metric " << metric;
469
470 metric = metrics::kMetricSuccessfulUpdateAttemptCount;
471 system_state->metrics_lib()->SendToUMA(metric,
472 attempt_count,
473 1, // min: 1 attempt
474 50, // max: 50 attempts
475 50); // num_buckets
476 LOG(INFO) << "Uploading " << attempt_count
477 << " for metric " << metric;
478
479 metric = metrics::kMetricSuccessfulUpdateUpdatesAbandonedCount;
480 LOG(INFO) << "Uploading " << updates_abandoned_count
481 << " (count) for metric " << metric;
482 system_state->metrics_lib()->SendToUMA(metric,
483 updates_abandoned_count,
484 0, // min: 0 counts
485 49, // max: 49 counts
486 50); // num_buckets
487 }
488
ReportRollbackMetrics(SystemState * system_state,RollbackResult result)489 void ReportRollbackMetrics(SystemState *system_state,
490 RollbackResult result) {
491 string metric;
492 int value;
493
494 metric = metrics::kMetricRollbackResult;
495 value = static_cast<int>(result);
496 LOG(INFO) << "Sending " << value << " for metric " << metric << " (enum)";
497 system_state->metrics_lib()->SendEnumToUMA(
498 metric,
499 value,
500 static_cast<int>(metrics::RollbackResult::kNumConstants));
501 }
502
ReportCertificateCheckMetrics(SystemState * system_state,ServerToCheck server_to_check,CertificateCheckResult result)503 void ReportCertificateCheckMetrics(SystemState* system_state,
504 ServerToCheck server_to_check,
505 CertificateCheckResult result) {
506 string metric;
507 switch (server_to_check) {
508 case ServerToCheck::kUpdate:
509 metric = kMetricCertificateCheckUpdateCheck;
510 break;
511 case ServerToCheck::kDownload:
512 metric = kMetricCertificateCheckDownload;
513 break;
514 case ServerToCheck::kNone:
515 return;
516 }
517 LOG(INFO) << "Uploading " << static_cast<int>(result) << " for metric "
518 << metric;
519 system_state->metrics_lib()->SendEnumToUMA(
520 metric, static_cast<int>(result),
521 static_cast<int>(CertificateCheckResult::kNumConstants));
522 }
523
524 } // namespace metrics
525
526 } // namespace chromeos_update_engine
527