1 // 2 // Copyright (C) 2015 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_utils.h" 18 19 #include <string> 20 21 #include <base/time/time.h> 22 23 #include "update_engine/common/clock_interface.h" 24 #include "update_engine/common/constants.h" 25 #include "update_engine/common/utils.h" 26 27 using base::Time; 28 using base::TimeDelta; 29 30 namespace chromeos_update_engine { 31 namespace metrics_utils { 32 33 metrics::AttemptResult GetAttemptResult(ErrorCode code) { 34 ErrorCode base_code = static_cast<ErrorCode>( 35 static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags)); 36 37 switch (base_code) { 38 case ErrorCode::kSuccess: 39 return metrics::AttemptResult::kUpdateSucceeded; 40 41 case ErrorCode::kUpdatedButNotActive: 42 return metrics::AttemptResult::kUpdateSucceededNotActive; 43 44 case ErrorCode::kDownloadTransferError: 45 case ErrorCode::kInternalLibCurlError: 46 case ErrorCode::kUnresolvedHostError: 47 case ErrorCode::kUnresolvedHostRecovered: 48 return metrics::AttemptResult::kPayloadDownloadError; 49 50 case ErrorCode::kDownloadInvalidMetadataSize: 51 case ErrorCode::kDownloadInvalidMetadataMagicString: 52 case ErrorCode::kDownloadMetadataSignatureError: 53 case ErrorCode::kDownloadMetadataSignatureVerificationError: 54 case ErrorCode::kPayloadMismatchedType: 55 case ErrorCode::kUnsupportedMajorPayloadVersion: 56 case ErrorCode::kUnsupportedMinorPayloadVersion: 57 case ErrorCode::kDownloadNewPartitionInfoError: 58 case ErrorCode::kDownloadSignatureMissingInManifest: 59 case ErrorCode::kDownloadManifestParseError: 60 case ErrorCode::kDownloadOperationHashMissingError: 61 return metrics::AttemptResult::kMetadataMalformed; 62 63 case ErrorCode::kDownloadOperationHashMismatch: 64 case ErrorCode::kDownloadOperationHashVerificationError: 65 return metrics::AttemptResult::kOperationMalformed; 66 67 case ErrorCode::kDownloadOperationExecutionError: 68 case ErrorCode::kInstallDeviceOpenError: 69 case ErrorCode::kKernelDeviceOpenError: 70 case ErrorCode::kDownloadWriteError: 71 case ErrorCode::kFilesystemCopierError: 72 case ErrorCode::kFilesystemVerifierError: 73 case ErrorCode::kVerityCalculationError: 74 case ErrorCode::kNotEnoughSpace: 75 case ErrorCode::kDeviceCorrupted: 76 return metrics::AttemptResult::kOperationExecutionError; 77 78 case ErrorCode::kDownloadMetadataSignatureMismatch: 79 return metrics::AttemptResult::kMetadataVerificationFailed; 80 81 case ErrorCode::kPayloadSizeMismatchError: 82 case ErrorCode::kPayloadHashMismatchError: 83 case ErrorCode::kDownloadPayloadVerificationError: 84 case ErrorCode::kSignedDeltaPayloadExpectedError: 85 case ErrorCode::kDownloadPayloadPubKeyVerificationError: 86 case ErrorCode::kPayloadTimestampError: 87 return metrics::AttemptResult::kPayloadVerificationFailed; 88 89 case ErrorCode::kNewRootfsVerificationError: 90 case ErrorCode::kNewKernelVerificationError: 91 case ErrorCode::kRollbackNotPossible: 92 return metrics::AttemptResult::kVerificationFailed; 93 94 case ErrorCode::kPostinstallRunnerError: 95 case ErrorCode::kPostinstallBootedFromFirmwareB: 96 case ErrorCode::kPostinstallFirmwareRONotUpdatable: 97 case ErrorCode::kPostInstallMountError: 98 return metrics::AttemptResult::kPostInstallFailed; 99 100 case ErrorCode::kUserCanceled: 101 return metrics::AttemptResult::kUpdateCanceled; 102 103 // We should never get these errors in the update-attempt stage so 104 // return internal error if this happens. 105 case ErrorCode::kError: 106 case ErrorCode::kOmahaRequestXMLParseError: 107 case ErrorCode::kOmahaRequestError: 108 case ErrorCode::kOmahaResponseHandlerError: 109 case ErrorCode::kDownloadStateInitializationError: 110 case ErrorCode::kOmahaRequestEmptyResponseError: 111 case ErrorCode::kDownloadInvalidMetadataSignature: 112 case ErrorCode::kOmahaResponseInvalid: 113 case ErrorCode::kOmahaUpdateIgnoredPerPolicy: 114 case ErrorCode::kOmahaErrorInHTTPResponse: 115 case ErrorCode::kDownloadMetadataSignatureMissingError: 116 case ErrorCode::kOmahaUpdateDeferredForBackoff: 117 case ErrorCode::kPostinstallPowerwashError: 118 case ErrorCode::kUpdateCanceledByChannelChange: 119 case ErrorCode::kOmahaRequestXMLHasEntityDecl: 120 case ErrorCode::kOmahaUpdateIgnoredOverCellular: 121 case ErrorCode::kNoUpdate: 122 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError: 123 case ErrorCode::kPackageExcludedFromUpdate: 124 return metrics::AttemptResult::kInternalError; 125 126 case ErrorCode::kOmahaUpdateDeferredPerPolicy: 127 case ErrorCode::kNonCriticalUpdateInOOBE: 128 return metrics::AttemptResult::kUpdateSkipped; 129 130 // Special flags. These can't happen (we mask them out above) but 131 // the compiler doesn't know that. Just break out so we can warn and 132 // return |kInternalError|. 133 case ErrorCode::kUmaReportedMax: 134 case ErrorCode::kOmahaRequestHTTPResponseBase: 135 case ErrorCode::kDevModeFlag: 136 case ErrorCode::kResumedFlag: 137 case ErrorCode::kTestImageFlag: 138 case ErrorCode::kTestOmahaUrlFlag: 139 case ErrorCode::kSpecialFlags: 140 break; 141 } 142 143 LOG(ERROR) << "Unexpected error code " << base_code; 144 return metrics::AttemptResult::kInternalError; 145 } 146 147 metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) { 148 ErrorCode base_code = static_cast<ErrorCode>( 149 static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags)); 150 151 if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) { 152 int http_status = 153 static_cast<int>(base_code) - 154 static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase); 155 if (http_status >= 200 && http_status <= 599) { 156 return static_cast<metrics::DownloadErrorCode>( 157 static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) + 158 http_status - 200); 159 } else if (http_status == 0) { 160 // The code is using HTTP Status 0 for "Unable to get http 161 // response code." 162 return metrics::DownloadErrorCode::kDownloadError; 163 } 164 LOG(WARNING) << "Unexpected HTTP status code " << http_status; 165 return metrics::DownloadErrorCode::kHttpStatusOther; 166 } 167 168 switch (base_code) { 169 // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide 170 // variety of errors (proxy errors, host not reachable, timeouts etc.). 171 // 172 // For now just map that to kDownloading. See http://crbug.com/355745 173 // for how we plan to add more detail in the future. 174 case ErrorCode::kDownloadTransferError: 175 return metrics::DownloadErrorCode::kDownloadError; 176 177 case ErrorCode::kInternalLibCurlError: 178 return metrics::DownloadErrorCode::kInternalLibCurlError; 179 case ErrorCode::kUnresolvedHostError: 180 return metrics::DownloadErrorCode::kUnresolvedHostError; 181 case ErrorCode::kUnresolvedHostRecovered: 182 return metrics::DownloadErrorCode::kUnresolvedHostRecovered; 183 184 // All of these error codes are not related to downloading so break 185 // out so we can warn and return InputMalformed. 186 case ErrorCode::kSuccess: 187 case ErrorCode::kError: 188 case ErrorCode::kOmahaRequestError: 189 case ErrorCode::kOmahaResponseHandlerError: 190 case ErrorCode::kFilesystemCopierError: 191 case ErrorCode::kPostinstallRunnerError: 192 case ErrorCode::kPostInstallMountError: 193 case ErrorCode::kPayloadMismatchedType: 194 case ErrorCode::kInstallDeviceOpenError: 195 case ErrorCode::kKernelDeviceOpenError: 196 case ErrorCode::kPayloadHashMismatchError: 197 case ErrorCode::kPayloadSizeMismatchError: 198 case ErrorCode::kDownloadPayloadVerificationError: 199 case ErrorCode::kDownloadNewPartitionInfoError: 200 case ErrorCode::kDownloadWriteError: 201 case ErrorCode::kNewRootfsVerificationError: 202 case ErrorCode::kNewKernelVerificationError: 203 case ErrorCode::kSignedDeltaPayloadExpectedError: 204 case ErrorCode::kDownloadPayloadPubKeyVerificationError: 205 case ErrorCode::kPostinstallBootedFromFirmwareB: 206 case ErrorCode::kDownloadStateInitializationError: 207 case ErrorCode::kDownloadInvalidMetadataMagicString: 208 case ErrorCode::kDownloadSignatureMissingInManifest: 209 case ErrorCode::kDownloadManifestParseError: 210 case ErrorCode::kDownloadMetadataSignatureError: 211 case ErrorCode::kDownloadMetadataSignatureVerificationError: 212 case ErrorCode::kDownloadMetadataSignatureMismatch: 213 case ErrorCode::kDownloadOperationHashVerificationError: 214 case ErrorCode::kDownloadOperationExecutionError: 215 case ErrorCode::kDownloadOperationHashMismatch: 216 case ErrorCode::kOmahaRequestEmptyResponseError: 217 case ErrorCode::kOmahaRequestXMLParseError: 218 case ErrorCode::kDownloadInvalidMetadataSize: 219 case ErrorCode::kDownloadInvalidMetadataSignature: 220 case ErrorCode::kOmahaResponseInvalid: 221 case ErrorCode::kOmahaUpdateIgnoredPerPolicy: 222 case ErrorCode::kOmahaUpdateDeferredPerPolicy: 223 case ErrorCode::kNonCriticalUpdateInOOBE: 224 case ErrorCode::kOmahaErrorInHTTPResponse: 225 case ErrorCode::kDownloadOperationHashMissingError: 226 case ErrorCode::kDownloadMetadataSignatureMissingError: 227 case ErrorCode::kOmahaUpdateDeferredForBackoff: 228 case ErrorCode::kPostinstallPowerwashError: 229 case ErrorCode::kUpdateCanceledByChannelChange: 230 case ErrorCode::kPostinstallFirmwareRONotUpdatable: 231 case ErrorCode::kUnsupportedMajorPayloadVersion: 232 case ErrorCode::kUnsupportedMinorPayloadVersion: 233 case ErrorCode::kOmahaRequestXMLHasEntityDecl: 234 case ErrorCode::kFilesystemVerifierError: 235 case ErrorCode::kUserCanceled: 236 case ErrorCode::kOmahaUpdateIgnoredOverCellular: 237 case ErrorCode::kPayloadTimestampError: 238 case ErrorCode::kUpdatedButNotActive: 239 case ErrorCode::kNoUpdate: 240 case ErrorCode::kRollbackNotPossible: 241 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError: 242 case ErrorCode::kVerityCalculationError: 243 case ErrorCode::kNotEnoughSpace: 244 case ErrorCode::kDeviceCorrupted: 245 case ErrorCode::kPackageExcludedFromUpdate: 246 break; 247 248 // Special flags. These can't happen (we mask them out above) but 249 // the compiler doesn't know that. Just break out so we can warn and 250 // return |kInputMalformed|. 251 case ErrorCode::kUmaReportedMax: 252 case ErrorCode::kOmahaRequestHTTPResponseBase: 253 case ErrorCode::kDevModeFlag: 254 case ErrorCode::kResumedFlag: 255 case ErrorCode::kTestImageFlag: 256 case ErrorCode::kTestOmahaUrlFlag: 257 case ErrorCode::kSpecialFlags: 258 LOG(ERROR) << "Unexpected error code " << base_code; 259 break; 260 } 261 262 return metrics::DownloadErrorCode::kInputMalformed; 263 } 264 265 metrics::ConnectionType GetConnectionType(ConnectionType type, 266 ConnectionTethering tethering) { 267 switch (type) { 268 case ConnectionType::kUnknown: 269 return metrics::ConnectionType::kUnknown; 270 271 case ConnectionType::kDisconnected: 272 return metrics::ConnectionType::kDisconnected; 273 274 case ConnectionType::kEthernet: 275 if (tethering == ConnectionTethering::kConfirmed) 276 return metrics::ConnectionType::kTetheredEthernet; 277 else 278 return metrics::ConnectionType::kEthernet; 279 280 case ConnectionType::kWifi: 281 if (tethering == ConnectionTethering::kConfirmed) 282 return metrics::ConnectionType::kTetheredWifi; 283 else 284 return metrics::ConnectionType::kWifi; 285 286 case ConnectionType::kCellular: 287 return metrics::ConnectionType::kCellular; 288 } 289 290 LOG(ERROR) << "Unexpected network connection type: type=" 291 << static_cast<int>(type) 292 << ", tethering=" << static_cast<int>(tethering); 293 294 return metrics::ConnectionType::kUnknown; 295 } 296 297 int64_t GetPersistedValue(const std::string& key, PrefsInterface* prefs) { 298 CHECK(prefs); 299 if (!prefs->Exists(key)) 300 return 0; 301 302 int64_t stored_value; 303 if (!prefs->GetInt64(key, &stored_value)) 304 return 0; 305 306 if (stored_value < 0) { 307 LOG(ERROR) << key << ": Invalid value (" << stored_value 308 << ") in persisted state. Defaulting to 0"; 309 return 0; 310 } 311 312 return stored_value; 313 } 314 315 void SetNumReboots(int64_t num_reboots, PrefsInterface* prefs) { 316 CHECK(prefs); 317 prefs->SetInt64(kPrefsNumReboots, num_reboots); 318 LOG(INFO) << "Number of Reboots during current update attempt = " 319 << num_reboots; 320 } 321 322 void SetPayloadAttemptNumber(int64_t payload_attempt_number, 323 PrefsInterface* prefs) { 324 CHECK(prefs); 325 prefs->SetInt64(kPrefsPayloadAttemptNumber, payload_attempt_number); 326 LOG(INFO) << "Payload Attempt Number = " << payload_attempt_number; 327 } 328 329 void SetSystemUpdatedMarker(ClockInterface* clock, PrefsInterface* prefs) { 330 CHECK(prefs); 331 CHECK(clock); 332 Time update_finish_time = clock->GetMonotonicTime(); 333 prefs->SetInt64(kPrefsSystemUpdatedMarker, 334 update_finish_time.ToInternalValue()); 335 LOG(INFO) << "Updated Marker = " << utils::ToString(update_finish_time); 336 } 337 338 void SetUpdateTimestampStart(const Time& update_start_time, 339 PrefsInterface* prefs) { 340 CHECK(prefs); 341 prefs->SetInt64(kPrefsUpdateTimestampStart, 342 update_start_time.ToInternalValue()); 343 LOG(INFO) << "Update Monotonic Timestamp Start = " 344 << utils::ToString(update_start_time); 345 } 346 347 void SetUpdateBootTimestampStart(const base::Time& update_start_boot_time, 348 PrefsInterface* prefs) { 349 CHECK(prefs); 350 prefs->SetInt64(kPrefsUpdateBootTimestampStart, 351 update_start_boot_time.ToInternalValue()); 352 LOG(INFO) << "Update Boot Timestamp Start = " 353 << utils::ToString(update_start_boot_time); 354 } 355 356 bool LoadAndReportTimeToReboot(MetricsReporterInterface* metrics_reporter, 357 PrefsInterface* prefs, 358 ClockInterface* clock) { 359 CHECK(prefs); 360 CHECK(clock); 361 int64_t stored_value = GetPersistedValue(kPrefsSystemUpdatedMarker, prefs); 362 if (stored_value == 0) 363 return false; 364 365 Time system_updated_at = Time::FromInternalValue(stored_value); 366 TimeDelta time_to_reboot = clock->GetMonotonicTime() - system_updated_at; 367 if (time_to_reboot.ToInternalValue() < 0) { 368 LOG(ERROR) << "time_to_reboot is negative - system_updated_at: " 369 << utils::ToString(system_updated_at); 370 return false; 371 } 372 metrics_reporter->ReportTimeToReboot(time_to_reboot.InMinutes()); 373 return true; 374 } 375 376 } // namespace metrics_utils 377 } // namespace chromeos_update_engine 378