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