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