// // Copyright (C) 2015 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "update_engine/metrics_utils.h" #include <string> #include <base/time/time.h> #include "update_engine/common/clock_interface.h" #include "update_engine/common/prefs_interface.h" #include "update_engine/system_state.h" using base::Time; using base::TimeDelta; namespace chromeos_update_engine { namespace metrics_utils { metrics::AttemptResult GetAttemptResult(ErrorCode code) { ErrorCode base_code = static_cast<ErrorCode>( static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags)); switch (base_code) { case ErrorCode::kSuccess: return metrics::AttemptResult::kUpdateSucceeded; case ErrorCode::kDownloadTransferError: return metrics::AttemptResult::kPayloadDownloadError; case ErrorCode::kDownloadInvalidMetadataSize: case ErrorCode::kDownloadInvalidMetadataMagicString: case ErrorCode::kDownloadMetadataSignatureError: case ErrorCode::kDownloadMetadataSignatureVerificationError: case ErrorCode::kPayloadMismatchedType: case ErrorCode::kUnsupportedMajorPayloadVersion: case ErrorCode::kUnsupportedMinorPayloadVersion: case ErrorCode::kDownloadNewPartitionInfoError: case ErrorCode::kDownloadSignatureMissingInManifest: case ErrorCode::kDownloadManifestParseError: case ErrorCode::kDownloadOperationHashMissingError: return metrics::AttemptResult::kMetadataMalformed; case ErrorCode::kDownloadOperationHashMismatch: case ErrorCode::kDownloadOperationHashVerificationError: return metrics::AttemptResult::kOperationMalformed; case ErrorCode::kDownloadOperationExecutionError: case ErrorCode::kInstallDeviceOpenError: case ErrorCode::kKernelDeviceOpenError: case ErrorCode::kDownloadWriteError: case ErrorCode::kFilesystemCopierError: case ErrorCode::kFilesystemVerifierError: return metrics::AttemptResult::kOperationExecutionError; case ErrorCode::kDownloadMetadataSignatureMismatch: return metrics::AttemptResult::kMetadataVerificationFailed; case ErrorCode::kPayloadSizeMismatchError: case ErrorCode::kPayloadHashMismatchError: case ErrorCode::kDownloadPayloadVerificationError: case ErrorCode::kSignedDeltaPayloadExpectedError: case ErrorCode::kDownloadPayloadPubKeyVerificationError: return metrics::AttemptResult::kPayloadVerificationFailed; case ErrorCode::kNewRootfsVerificationError: case ErrorCode::kNewKernelVerificationError: return metrics::AttemptResult::kVerificationFailed; case ErrorCode::kPostinstallRunnerError: case ErrorCode::kPostinstallBootedFromFirmwareB: case ErrorCode::kPostinstallFirmwareRONotUpdatable: return metrics::AttemptResult::kPostInstallFailed; case ErrorCode::kUserCanceled: return metrics::AttemptResult::kUpdateCanceled; // We should never get these errors in the update-attempt stage so // return internal error if this happens. case ErrorCode::kError: case ErrorCode::kOmahaRequestXMLParseError: case ErrorCode::kOmahaRequestError: case ErrorCode::kOmahaResponseHandlerError: case ErrorCode::kDownloadStateInitializationError: case ErrorCode::kOmahaRequestEmptyResponseError: case ErrorCode::kDownloadInvalidMetadataSignature: case ErrorCode::kOmahaResponseInvalid: case ErrorCode::kOmahaUpdateIgnoredPerPolicy: // TODO(deymo): The next two items belong in their own category; they // should not be counted as internal errors. b/27112092 case ErrorCode::kOmahaUpdateDeferredPerPolicy: case ErrorCode::kNonCriticalUpdateInOOBE: case ErrorCode::kOmahaErrorInHTTPResponse: case ErrorCode::kDownloadMetadataSignatureMissingError: case ErrorCode::kOmahaUpdateDeferredForBackoff: case ErrorCode::kPostinstallPowerwashError: case ErrorCode::kUpdateCanceledByChannelChange: case ErrorCode::kOmahaRequestXMLHasEntityDecl: return metrics::AttemptResult::kInternalError; // Special flags. These can't happen (we mask them out above) but // the compiler doesn't know that. Just break out so we can warn and // return |kInternalError|. case ErrorCode::kUmaReportedMax: case ErrorCode::kOmahaRequestHTTPResponseBase: case ErrorCode::kDevModeFlag: case ErrorCode::kResumedFlag: case ErrorCode::kTestImageFlag: case ErrorCode::kTestOmahaUrlFlag: case ErrorCode::kSpecialFlags: break; } LOG(ERROR) << "Unexpected error code " << base_code; return metrics::AttemptResult::kInternalError; } metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) { ErrorCode base_code = static_cast<ErrorCode>( static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags)); if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) { int http_status = static_cast<int>(base_code) - static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase); if (http_status >= 200 && http_status <= 599) { return static_cast<metrics::DownloadErrorCode>( static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) + http_status - 200); } else if (http_status == 0) { // The code is using HTTP Status 0 for "Unable to get http // response code." return metrics::DownloadErrorCode::kDownloadError; } LOG(WARNING) << "Unexpected HTTP status code " << http_status; return metrics::DownloadErrorCode::kHttpStatusOther; } switch (base_code) { // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide // variety of errors (proxy errors, host not reachable, timeouts etc.). // // For now just map that to kDownloading. See http://crbug.com/355745 // for how we plan to add more detail in the future. case ErrorCode::kDownloadTransferError: return metrics::DownloadErrorCode::kDownloadError; // All of these error codes are not related to downloading so break // out so we can warn and return InputMalformed. case ErrorCode::kSuccess: case ErrorCode::kError: case ErrorCode::kOmahaRequestError: case ErrorCode::kOmahaResponseHandlerError: case ErrorCode::kFilesystemCopierError: case ErrorCode::kPostinstallRunnerError: case ErrorCode::kPayloadMismatchedType: case ErrorCode::kInstallDeviceOpenError: case ErrorCode::kKernelDeviceOpenError: case ErrorCode::kPayloadHashMismatchError: case ErrorCode::kPayloadSizeMismatchError: case ErrorCode::kDownloadPayloadVerificationError: case ErrorCode::kDownloadNewPartitionInfoError: case ErrorCode::kDownloadWriteError: case ErrorCode::kNewRootfsVerificationError: case ErrorCode::kNewKernelVerificationError: case ErrorCode::kSignedDeltaPayloadExpectedError: case ErrorCode::kDownloadPayloadPubKeyVerificationError: case ErrorCode::kPostinstallBootedFromFirmwareB: case ErrorCode::kDownloadStateInitializationError: case ErrorCode::kDownloadInvalidMetadataMagicString: case ErrorCode::kDownloadSignatureMissingInManifest: case ErrorCode::kDownloadManifestParseError: case ErrorCode::kDownloadMetadataSignatureError: case ErrorCode::kDownloadMetadataSignatureVerificationError: case ErrorCode::kDownloadMetadataSignatureMismatch: case ErrorCode::kDownloadOperationHashVerificationError: case ErrorCode::kDownloadOperationExecutionError: case ErrorCode::kDownloadOperationHashMismatch: case ErrorCode::kOmahaRequestEmptyResponseError: case ErrorCode::kOmahaRequestXMLParseError: case ErrorCode::kDownloadInvalidMetadataSize: case ErrorCode::kDownloadInvalidMetadataSignature: case ErrorCode::kOmahaResponseInvalid: case ErrorCode::kOmahaUpdateIgnoredPerPolicy: case ErrorCode::kOmahaUpdateDeferredPerPolicy: case ErrorCode::kNonCriticalUpdateInOOBE: case ErrorCode::kOmahaErrorInHTTPResponse: case ErrorCode::kDownloadOperationHashMissingError: case ErrorCode::kDownloadMetadataSignatureMissingError: case ErrorCode::kOmahaUpdateDeferredForBackoff: case ErrorCode::kPostinstallPowerwashError: case ErrorCode::kUpdateCanceledByChannelChange: case ErrorCode::kPostinstallFirmwareRONotUpdatable: case ErrorCode::kUnsupportedMajorPayloadVersion: case ErrorCode::kUnsupportedMinorPayloadVersion: case ErrorCode::kOmahaRequestXMLHasEntityDecl: case ErrorCode::kFilesystemVerifierError: case ErrorCode::kUserCanceled: break; // Special flags. These can't happen (we mask them out above) but // the compiler doesn't know that. Just break out so we can warn and // return |kInputMalformed|. case ErrorCode::kUmaReportedMax: case ErrorCode::kOmahaRequestHTTPResponseBase: case ErrorCode::kDevModeFlag: case ErrorCode::kResumedFlag: case ErrorCode::kTestImageFlag: case ErrorCode::kTestOmahaUrlFlag: case ErrorCode::kSpecialFlags: LOG(ERROR) << "Unexpected error code " << base_code; break; } return metrics::DownloadErrorCode::kInputMalformed; } metrics::ConnectionType GetConnectionType(ConnectionType type, ConnectionTethering tethering) { switch (type) { case ConnectionType::kUnknown: return metrics::ConnectionType::kUnknown; case ConnectionType::kEthernet: if (tethering == ConnectionTethering::kConfirmed) return metrics::ConnectionType::kTetheredEthernet; else return metrics::ConnectionType::kEthernet; case ConnectionType::kWifi: if (tethering == ConnectionTethering::kConfirmed) return metrics::ConnectionType::kTetheredWifi; else return metrics::ConnectionType::kWifi; case ConnectionType::kWimax: return metrics::ConnectionType::kWimax; case ConnectionType::kBluetooth: return metrics::ConnectionType::kBluetooth; case ConnectionType::kCellular: return metrics::ConnectionType::kCellular; } LOG(ERROR) << "Unexpected network connection type: type=" << static_cast<int>(type) << ", tethering=" << static_cast<int>(tethering); return metrics::ConnectionType::kUnknown; } bool WallclockDurationHelper(SystemState* system_state, const std::string& state_variable_key, TimeDelta* out_duration) { bool ret = false; Time now = system_state->clock()->GetWallclockTime(); int64_t stored_value; if (system_state->prefs()->GetInt64(state_variable_key, &stored_value)) { Time stored_time = Time::FromInternalValue(stored_value); if (stored_time > now) { LOG(ERROR) << "Stored time-stamp used for " << state_variable_key << " is in the future."; } else { *out_duration = now - stored_time; ret = true; } } if (!system_state->prefs()->SetInt64(state_variable_key, now.ToInternalValue())) { LOG(ERROR) << "Error storing time-stamp in " << state_variable_key; } return ret; } bool MonotonicDurationHelper(SystemState* system_state, int64_t* storage, TimeDelta* out_duration) { bool ret = false; Time now = system_state->clock()->GetMonotonicTime(); if (*storage != 0) { Time stored_time = Time::FromInternalValue(*storage); *out_duration = now - stored_time; ret = true; } *storage = now.ToInternalValue(); return ret; } } // namespace metrics_utils } // namespace chromeos_update_engine