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