blob: 263bacd2171bc9be54d5706ecb8586e0cb3bf247 [file] [log] [blame]
Alex Deymo38429cf2015-11-11 18:27:22 -08001//
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
Alex Deymoa2591792015-11-17 00:39:40 -030019#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
27using base::Time;
28using base::TimeDelta;
29
Alex Deymo38429cf2015-11-11 18:27:22 -080030namespace chromeos_update_engine {
31namespace metrics_utils {
32
33metrics::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
Alex Deymo1f19dcc2016-02-03 09:22:17 -080088 case ErrorCode::kUserCanceled:
89 return metrics::AttemptResult::kUpdateCanceled;
90
Alex Deymo38429cf2015-11-11 18:27:22 -080091 // 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:
Kevin Cernekee2494e282016-03-29 18:03:53 -0700102 // TODO(deymo): The next two items belong in their own category; they
103 // should not be counted as internal errors. b/27112092
Alex Deymo38429cf2015-11-11 18:27:22 -0800104 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
Kevin Cernekee2494e282016-03-29 18:03:53 -0700105 case ErrorCode::kNonCriticalUpdateInOOBE:
Alex Deymo38429cf2015-11-11 18:27:22 -0800106 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
131metrics::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:
Kevin Cernekee2494e282016-03-29 18:03:53 -0700199 case ErrorCode::kNonCriticalUpdateInOOBE:
Alex Deymo38429cf2015-11-11 18:27:22 -0800200 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:
Alex Deymo1f19dcc2016-02-03 09:22:17 -0800211 case ErrorCode::kUserCanceled:
Alex Deymo38429cf2015-11-11 18:27:22 -0800212 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
Sen Jiang255e22b2016-05-20 16:15:29 -0700231metrics::ConnectionType GetConnectionType(ConnectionType type,
232 ConnectionTethering tethering) {
Alex Deymo38429cf2015-11-11 18:27:22 -0800233 switch (type) {
Sen Jiang255e22b2016-05-20 16:15:29 -0700234 case ConnectionType::kUnknown:
Alex Deymo38429cf2015-11-11 18:27:22 -0800235 return metrics::ConnectionType::kUnknown;
236
Sen Jiang255e22b2016-05-20 16:15:29 -0700237 case ConnectionType::kEthernet:
238 if (tethering == ConnectionTethering::kConfirmed)
Alex Deymo38429cf2015-11-11 18:27:22 -0800239 return metrics::ConnectionType::kTetheredEthernet;
240 else
241 return metrics::ConnectionType::kEthernet;
242
Sen Jiang255e22b2016-05-20 16:15:29 -0700243 case ConnectionType::kWifi:
244 if (tethering == ConnectionTethering::kConfirmed)
Alex Deymo38429cf2015-11-11 18:27:22 -0800245 return metrics::ConnectionType::kTetheredWifi;
246 else
247 return metrics::ConnectionType::kWifi;
248
Sen Jiang255e22b2016-05-20 16:15:29 -0700249 case ConnectionType::kWimax:
Alex Deymo38429cf2015-11-11 18:27:22 -0800250 return metrics::ConnectionType::kWimax;
251
Sen Jiang255e22b2016-05-20 16:15:29 -0700252 case ConnectionType::kBluetooth:
Alex Deymo38429cf2015-11-11 18:27:22 -0800253 return metrics::ConnectionType::kBluetooth;
254
Sen Jiang255e22b2016-05-20 16:15:29 -0700255 case ConnectionType::kCellular:
Alex Deymo38429cf2015-11-11 18:27:22 -0800256 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
Alex Deymoa2591792015-11-17 00:39:40 -0300266bool 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
292bool 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
Alex Deymo38429cf2015-11-11 18:27:22 -0800308} // namespace metrics_utils
309} // namespace chromeos_update_engine