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/prefs_interface.h" 25 #include "update_engine/system_state.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::kDownloadTransferError: 42 return metrics::AttemptResult::kPayloadDownloadError; 43 44 case ErrorCode::kDownloadInvalidMetadataSize: 45 case ErrorCode::kDownloadInvalidMetadataMagicString: 46 case ErrorCode::kDownloadMetadataSignatureError: 47 case ErrorCode::kDownloadMetadataSignatureVerificationError: 48 case ErrorCode::kPayloadMismatchedType: 49 case ErrorCode::kUnsupportedMajorPayloadVersion: 50 case ErrorCode::kUnsupportedMinorPayloadVersion: 51 case ErrorCode::kDownloadNewPartitionInfoError: 52 case ErrorCode::kDownloadSignatureMissingInManifest: 53 case ErrorCode::kDownloadManifestParseError: 54 case ErrorCode::kDownloadOperationHashMissingError: 55 return metrics::AttemptResult::kMetadataMalformed; 56 57 case ErrorCode::kDownloadOperationHashMismatch: 58 case ErrorCode::kDownloadOperationHashVerificationError: 59 return metrics::AttemptResult::kOperationMalformed; 60 61 case ErrorCode::kDownloadOperationExecutionError: 62 case ErrorCode::kInstallDeviceOpenError: 63 case ErrorCode::kKernelDeviceOpenError: 64 case ErrorCode::kDownloadWriteError: 65 case ErrorCode::kFilesystemCopierError: 66 case ErrorCode::kFilesystemVerifierError: 67 return metrics::AttemptResult::kOperationExecutionError; 68 69 case ErrorCode::kDownloadMetadataSignatureMismatch: 70 return metrics::AttemptResult::kMetadataVerificationFailed; 71 72 case ErrorCode::kPayloadSizeMismatchError: 73 case ErrorCode::kPayloadHashMismatchError: 74 case ErrorCode::kDownloadPayloadVerificationError: 75 case ErrorCode::kSignedDeltaPayloadExpectedError: 76 case ErrorCode::kDownloadPayloadPubKeyVerificationError: 77 return metrics::AttemptResult::kPayloadVerificationFailed; 78 79 case ErrorCode::kNewRootfsVerificationError: 80 case ErrorCode::kNewKernelVerificationError: 81 return metrics::AttemptResult::kVerificationFailed; 82 83 case ErrorCode::kPostinstallRunnerError: 84 case ErrorCode::kPostinstallBootedFromFirmwareB: 85 case ErrorCode::kPostinstallFirmwareRONotUpdatable: 86 return metrics::AttemptResult::kPostInstallFailed; 87 88 case ErrorCode::kUserCanceled: 89 return metrics::AttemptResult::kUpdateCanceled; 90 91 // We should never get these errors in the update-attempt stage so 92 // return internal error if this happens. 93 case ErrorCode::kError: 94 case ErrorCode::kOmahaRequestXMLParseError: 95 case ErrorCode::kOmahaRequestError: 96 case ErrorCode::kOmahaResponseHandlerError: 97 case ErrorCode::kDownloadStateInitializationError: 98 case ErrorCode::kOmahaRequestEmptyResponseError: 99 case ErrorCode::kDownloadInvalidMetadataSignature: 100 case ErrorCode::kOmahaResponseInvalid: 101 case ErrorCode::kOmahaUpdateIgnoredPerPolicy: 102 // TODO(deymo): The next two items belong in their own category; they 103 // should not be counted as internal errors. b/27112092 104 case ErrorCode::kOmahaUpdateDeferredPerPolicy: 105 case ErrorCode::kNonCriticalUpdateInOOBE: 106 case ErrorCode::kOmahaErrorInHTTPResponse: 107 case ErrorCode::kDownloadMetadataSignatureMissingError: 108 case ErrorCode::kOmahaUpdateDeferredForBackoff: 109 case ErrorCode::kPostinstallPowerwashError: 110 case ErrorCode::kUpdateCanceledByChannelChange: 111 case ErrorCode::kOmahaRequestXMLHasEntityDecl: 112 return metrics::AttemptResult::kInternalError; 113 114 // Special flags. These can't happen (we mask them out above) but 115 // the compiler doesn't know that. Just break out so we can warn and 116 // return |kInternalError|. 117 case ErrorCode::kUmaReportedMax: 118 case ErrorCode::kOmahaRequestHTTPResponseBase: 119 case ErrorCode::kDevModeFlag: 120 case ErrorCode::kResumedFlag: 121 case ErrorCode::kTestImageFlag: 122 case ErrorCode::kTestOmahaUrlFlag: 123 case ErrorCode::kSpecialFlags: 124 break; 125 } 126 127 LOG(ERROR) << "Unexpected error code " << base_code; 128 return metrics::AttemptResult::kInternalError; 129 } 130 131 metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) { 132 ErrorCode base_code = static_cast<ErrorCode>( 133 static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags)); 134 135 if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) { 136 int http_status = 137 static_cast<int>(base_code) - 138 static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase); 139 if (http_status >= 200 && http_status <= 599) { 140 return static_cast<metrics::DownloadErrorCode>( 141 static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) + 142 http_status - 200); 143 } else if (http_status == 0) { 144 // The code is using HTTP Status 0 for "Unable to get http 145 // response code." 146 return metrics::DownloadErrorCode::kDownloadError; 147 } 148 LOG(WARNING) << "Unexpected HTTP status code " << http_status; 149 return metrics::DownloadErrorCode::kHttpStatusOther; 150 } 151 152 switch (base_code) { 153 // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide 154 // variety of errors (proxy errors, host not reachable, timeouts etc.). 155 // 156 // For now just map that to kDownloading. See http://crbug.com/355745 157 // for how we plan to add more detail in the future. 158 case ErrorCode::kDownloadTransferError: 159 return metrics::DownloadErrorCode::kDownloadError; 160 161 // All of these error codes are not related to downloading so break 162 // out so we can warn and return InputMalformed. 163 case ErrorCode::kSuccess: 164 case ErrorCode::kError: 165 case ErrorCode::kOmahaRequestError: 166 case ErrorCode::kOmahaResponseHandlerError: 167 case ErrorCode::kFilesystemCopierError: 168 case ErrorCode::kPostinstallRunnerError: 169 case ErrorCode::kPayloadMismatchedType: 170 case ErrorCode::kInstallDeviceOpenError: 171 case ErrorCode::kKernelDeviceOpenError: 172 case ErrorCode::kPayloadHashMismatchError: 173 case ErrorCode::kPayloadSizeMismatchError: 174 case ErrorCode::kDownloadPayloadVerificationError: 175 case ErrorCode::kDownloadNewPartitionInfoError: 176 case ErrorCode::kDownloadWriteError: 177 case ErrorCode::kNewRootfsVerificationError: 178 case ErrorCode::kNewKernelVerificationError: 179 case ErrorCode::kSignedDeltaPayloadExpectedError: 180 case ErrorCode::kDownloadPayloadPubKeyVerificationError: 181 case ErrorCode::kPostinstallBootedFromFirmwareB: 182 case ErrorCode::kDownloadStateInitializationError: 183 case ErrorCode::kDownloadInvalidMetadataMagicString: 184 case ErrorCode::kDownloadSignatureMissingInManifest: 185 case ErrorCode::kDownloadManifestParseError: 186 case ErrorCode::kDownloadMetadataSignatureError: 187 case ErrorCode::kDownloadMetadataSignatureVerificationError: 188 case ErrorCode::kDownloadMetadataSignatureMismatch: 189 case ErrorCode::kDownloadOperationHashVerificationError: 190 case ErrorCode::kDownloadOperationExecutionError: 191 case ErrorCode::kDownloadOperationHashMismatch: 192 case ErrorCode::kOmahaRequestEmptyResponseError: 193 case ErrorCode::kOmahaRequestXMLParseError: 194 case ErrorCode::kDownloadInvalidMetadataSize: 195 case ErrorCode::kDownloadInvalidMetadataSignature: 196 case ErrorCode::kOmahaResponseInvalid: 197 case ErrorCode::kOmahaUpdateIgnoredPerPolicy: 198 case ErrorCode::kOmahaUpdateDeferredPerPolicy: 199 case ErrorCode::kNonCriticalUpdateInOOBE: 200 case ErrorCode::kOmahaErrorInHTTPResponse: 201 case ErrorCode::kDownloadOperationHashMissingError: 202 case ErrorCode::kDownloadMetadataSignatureMissingError: 203 case ErrorCode::kOmahaUpdateDeferredForBackoff: 204 case ErrorCode::kPostinstallPowerwashError: 205 case ErrorCode::kUpdateCanceledByChannelChange: 206 case ErrorCode::kPostinstallFirmwareRONotUpdatable: 207 case ErrorCode::kUnsupportedMajorPayloadVersion: 208 case ErrorCode::kUnsupportedMinorPayloadVersion: 209 case ErrorCode::kOmahaRequestXMLHasEntityDecl: 210 case ErrorCode::kFilesystemVerifierError: 211 case ErrorCode::kUserCanceled: 212 break; 213 214 // Special flags. These can't happen (we mask them out above) but 215 // the compiler doesn't know that. Just break out so we can warn and 216 // return |kInputMalformed|. 217 case ErrorCode::kUmaReportedMax: 218 case ErrorCode::kOmahaRequestHTTPResponseBase: 219 case ErrorCode::kDevModeFlag: 220 case ErrorCode::kResumedFlag: 221 case ErrorCode::kTestImageFlag: 222 case ErrorCode::kTestOmahaUrlFlag: 223 case ErrorCode::kSpecialFlags: 224 LOG(ERROR) << "Unexpected error code " << base_code; 225 break; 226 } 227 228 return metrics::DownloadErrorCode::kInputMalformed; 229 } 230 231 metrics::ConnectionType GetConnectionType(ConnectionType type, 232 ConnectionTethering tethering) { 233 switch (type) { 234 case ConnectionType::kUnknown: 235 return metrics::ConnectionType::kUnknown; 236 237 case ConnectionType::kEthernet: 238 if (tethering == ConnectionTethering::kConfirmed) 239 return metrics::ConnectionType::kTetheredEthernet; 240 else 241 return metrics::ConnectionType::kEthernet; 242 243 case ConnectionType::kWifi: 244 if (tethering == ConnectionTethering::kConfirmed) 245 return metrics::ConnectionType::kTetheredWifi; 246 else 247 return metrics::ConnectionType::kWifi; 248 249 case ConnectionType::kWimax: 250 return metrics::ConnectionType::kWimax; 251 252 case ConnectionType::kBluetooth: 253 return metrics::ConnectionType::kBluetooth; 254 255 case ConnectionType::kCellular: 256 return metrics::ConnectionType::kCellular; 257 } 258 259 LOG(ERROR) << "Unexpected network connection type: type=" 260 << static_cast<int>(type) 261 << ", tethering=" << static_cast<int>(tethering); 262 263 return metrics::ConnectionType::kUnknown; 264 } 265 266 bool WallclockDurationHelper(SystemState* system_state, 267 const std::string& state_variable_key, 268 TimeDelta* out_duration) { 269 bool ret = false; 270 271 Time now = system_state->clock()->GetWallclockTime(); 272 int64_t stored_value; 273 if (system_state->prefs()->GetInt64(state_variable_key, &stored_value)) { 274 Time stored_time = Time::FromInternalValue(stored_value); 275 if (stored_time > now) { 276 LOG(ERROR) << "Stored time-stamp used for " << state_variable_key 277 << " is in the future."; 278 } else { 279 *out_duration = now - stored_time; 280 ret = true; 281 } 282 } 283 284 if (!system_state->prefs()->SetInt64(state_variable_key, 285 now.ToInternalValue())) { 286 LOG(ERROR) << "Error storing time-stamp in " << state_variable_key; 287 } 288 289 return ret; 290 } 291 292 bool MonotonicDurationHelper(SystemState* system_state, 293 int64_t* storage, 294 TimeDelta* out_duration) { 295 bool ret = false; 296 297 Time now = system_state->clock()->GetMonotonicTime(); 298 if (*storage != 0) { 299 Time stored_time = Time::FromInternalValue(*storage); 300 *out_duration = now - stored_time; 301 ret = true; 302 } 303 *storage = now.ToInternalValue(); 304 305 return ret; 306 } 307 308 } // namespace metrics_utils 309 } // namespace chromeos_update_engine 310