blob: 2211a67bda0366cfb0ed015d6168deb0665e32aa [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
Sen Jiangfe522822017-10-31 15:14:11 -070042 case ErrorCode::kUpdatedButNotActive:
43 return metrics::AttemptResult::kUpdateSucceededNotActive;
44
Alex Deymo38429cf2015-11-11 18:27:22 -080045 case ErrorCode::kDownloadTransferError:
Amin Hassanid3d84212019-08-17 00:27:44 -070046 case ErrorCode::kInternalLibCurlError:
47 case ErrorCode::kUnresolvedHostError:
48 case ErrorCode::kUnresolvedHostRecovered:
Alex Deymo38429cf2015-11-11 18:27:22 -080049 return metrics::AttemptResult::kPayloadDownloadError;
50
51 case ErrorCode::kDownloadInvalidMetadataSize:
52 case ErrorCode::kDownloadInvalidMetadataMagicString:
53 case ErrorCode::kDownloadMetadataSignatureError:
54 case ErrorCode::kDownloadMetadataSignatureVerificationError:
55 case ErrorCode::kPayloadMismatchedType:
56 case ErrorCode::kUnsupportedMajorPayloadVersion:
57 case ErrorCode::kUnsupportedMinorPayloadVersion:
58 case ErrorCode::kDownloadNewPartitionInfoError:
59 case ErrorCode::kDownloadSignatureMissingInManifest:
60 case ErrorCode::kDownloadManifestParseError:
61 case ErrorCode::kDownloadOperationHashMissingError:
62 return metrics::AttemptResult::kMetadataMalformed;
63
64 case ErrorCode::kDownloadOperationHashMismatch:
65 case ErrorCode::kDownloadOperationHashVerificationError:
66 return metrics::AttemptResult::kOperationMalformed;
67
68 case ErrorCode::kDownloadOperationExecutionError:
69 case ErrorCode::kInstallDeviceOpenError:
70 case ErrorCode::kKernelDeviceOpenError:
71 case ErrorCode::kDownloadWriteError:
72 case ErrorCode::kFilesystemCopierError:
73 case ErrorCode::kFilesystemVerifierError:
Sen Jiang57f91802017-11-14 17:42:13 -080074 case ErrorCode::kVerityCalculationError:
Yifan Hong46e37d42019-12-13 12:01:42 -080075 case ErrorCode::kNotEnoughSpace:
Yifan Hong77279902019-12-17 16:38:21 -080076 case ErrorCode::kDeviceCorrupted:
Alex Deymo38429cf2015-11-11 18:27:22 -080077 return metrics::AttemptResult::kOperationExecutionError;
78
79 case ErrorCode::kDownloadMetadataSignatureMismatch:
80 return metrics::AttemptResult::kMetadataVerificationFailed;
81
82 case ErrorCode::kPayloadSizeMismatchError:
83 case ErrorCode::kPayloadHashMismatchError:
84 case ErrorCode::kDownloadPayloadVerificationError:
85 case ErrorCode::kSignedDeltaPayloadExpectedError:
86 case ErrorCode::kDownloadPayloadPubKeyVerificationError:
Sen Jiang8e768e92017-06-28 17:13:19 -070087 case ErrorCode::kPayloadTimestampError:
Alex Deymo38429cf2015-11-11 18:27:22 -080088 return metrics::AttemptResult::kPayloadVerificationFailed;
89
90 case ErrorCode::kNewRootfsVerificationError:
91 case ErrorCode::kNewKernelVerificationError:
Marton Hunyady199152d2018-05-07 19:08:48 +020092 case ErrorCode::kRollbackNotPossible:
Alex Deymo38429cf2015-11-11 18:27:22 -080093 return metrics::AttemptResult::kVerificationFailed;
94
95 case ErrorCode::kPostinstallRunnerError:
96 case ErrorCode::kPostinstallBootedFromFirmwareB:
97 case ErrorCode::kPostinstallFirmwareRONotUpdatable:
98 return metrics::AttemptResult::kPostInstallFailed;
99
Alex Deymo1f19dcc2016-02-03 09:22:17 -0800100 case ErrorCode::kUserCanceled:
101 return metrics::AttemptResult::kUpdateCanceled;
102
Alex Deymo38429cf2015-11-11 18:27:22 -0800103 // We should never get these errors in the update-attempt stage so
104 // return internal error if this happens.
105 case ErrorCode::kError:
106 case ErrorCode::kOmahaRequestXMLParseError:
107 case ErrorCode::kOmahaRequestError:
108 case ErrorCode::kOmahaResponseHandlerError:
109 case ErrorCode::kDownloadStateInitializationError:
110 case ErrorCode::kOmahaRequestEmptyResponseError:
111 case ErrorCode::kDownloadInvalidMetadataSignature:
112 case ErrorCode::kOmahaResponseInvalid:
113 case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
Alex Deymo38429cf2015-11-11 18:27:22 -0800114 case ErrorCode::kOmahaErrorInHTTPResponse:
115 case ErrorCode::kDownloadMetadataSignatureMissingError:
116 case ErrorCode::kOmahaUpdateDeferredForBackoff:
117 case ErrorCode::kPostinstallPowerwashError:
118 case ErrorCode::kUpdateCanceledByChannelChange:
119 case ErrorCode::kOmahaRequestXMLHasEntityDecl:
Weidong Guo421ff332017-04-17 10:08:38 -0700120 case ErrorCode::kOmahaUpdateIgnoredOverCellular:
Sen Jiang89e24c12018-03-22 18:05:44 -0700121 case ErrorCode::kNoUpdate:
Amin Hassani80f4d4c2018-05-16 13:34:00 -0700122 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700123 case ErrorCode::kPackageExcludedFromUpdate:
Alex Deymo38429cf2015-11-11 18:27:22 -0800124 return metrics::AttemptResult::kInternalError;
125
Andrewb57c16e2020-07-22 14:32:39 -0700126 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
127 case ErrorCode::kNonCriticalUpdateInOOBE:
128 return metrics::AttemptResult::kUpdateSkipped;
129
Alex Deymo38429cf2015-11-11 18:27:22 -0800130 // Special flags. These can't happen (we mask them out above) but
131 // the compiler doesn't know that. Just break out so we can warn and
132 // return |kInternalError|.
133 case ErrorCode::kUmaReportedMax:
134 case ErrorCode::kOmahaRequestHTTPResponseBase:
135 case ErrorCode::kDevModeFlag:
136 case ErrorCode::kResumedFlag:
137 case ErrorCode::kTestImageFlag:
138 case ErrorCode::kTestOmahaUrlFlag:
139 case ErrorCode::kSpecialFlags:
140 break;
141 }
142
143 LOG(ERROR) << "Unexpected error code " << base_code;
144 return metrics::AttemptResult::kInternalError;
145}
146
147metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) {
148 ErrorCode base_code = static_cast<ErrorCode>(
149 static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
150
151 if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
152 int http_status =
153 static_cast<int>(base_code) -
154 static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase);
155 if (http_status >= 200 && http_status <= 599) {
156 return static_cast<metrics::DownloadErrorCode>(
157 static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) +
158 http_status - 200);
159 } else if (http_status == 0) {
160 // The code is using HTTP Status 0 for "Unable to get http
161 // response code."
162 return metrics::DownloadErrorCode::kDownloadError;
163 }
164 LOG(WARNING) << "Unexpected HTTP status code " << http_status;
165 return metrics::DownloadErrorCode::kHttpStatusOther;
166 }
167
168 switch (base_code) {
169 // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide
170 // variety of errors (proxy errors, host not reachable, timeouts etc.).
171 //
172 // For now just map that to kDownloading. See http://crbug.com/355745
173 // for how we plan to add more detail in the future.
174 case ErrorCode::kDownloadTransferError:
175 return metrics::DownloadErrorCode::kDownloadError;
176
Amin Hassanid3d84212019-08-17 00:27:44 -0700177 case ErrorCode::kInternalLibCurlError:
178 return metrics::DownloadErrorCode::kInternalLibCurlError;
179 case ErrorCode::kUnresolvedHostError:
180 return metrics::DownloadErrorCode::kUnresolvedHostError;
181 case ErrorCode::kUnresolvedHostRecovered:
182 return metrics::DownloadErrorCode::kUnresolvedHostRecovered;
183
Alex Deymo38429cf2015-11-11 18:27:22 -0800184 // All of these error codes are not related to downloading so break
185 // out so we can warn and return InputMalformed.
186 case ErrorCode::kSuccess:
187 case ErrorCode::kError:
188 case ErrorCode::kOmahaRequestError:
189 case ErrorCode::kOmahaResponseHandlerError:
190 case ErrorCode::kFilesystemCopierError:
191 case ErrorCode::kPostinstallRunnerError:
192 case ErrorCode::kPayloadMismatchedType:
193 case ErrorCode::kInstallDeviceOpenError:
194 case ErrorCode::kKernelDeviceOpenError:
195 case ErrorCode::kPayloadHashMismatchError:
196 case ErrorCode::kPayloadSizeMismatchError:
197 case ErrorCode::kDownloadPayloadVerificationError:
198 case ErrorCode::kDownloadNewPartitionInfoError:
199 case ErrorCode::kDownloadWriteError:
200 case ErrorCode::kNewRootfsVerificationError:
201 case ErrorCode::kNewKernelVerificationError:
202 case ErrorCode::kSignedDeltaPayloadExpectedError:
203 case ErrorCode::kDownloadPayloadPubKeyVerificationError:
204 case ErrorCode::kPostinstallBootedFromFirmwareB:
205 case ErrorCode::kDownloadStateInitializationError:
206 case ErrorCode::kDownloadInvalidMetadataMagicString:
207 case ErrorCode::kDownloadSignatureMissingInManifest:
208 case ErrorCode::kDownloadManifestParseError:
209 case ErrorCode::kDownloadMetadataSignatureError:
210 case ErrorCode::kDownloadMetadataSignatureVerificationError:
211 case ErrorCode::kDownloadMetadataSignatureMismatch:
212 case ErrorCode::kDownloadOperationHashVerificationError:
213 case ErrorCode::kDownloadOperationExecutionError:
214 case ErrorCode::kDownloadOperationHashMismatch:
215 case ErrorCode::kOmahaRequestEmptyResponseError:
216 case ErrorCode::kOmahaRequestXMLParseError:
217 case ErrorCode::kDownloadInvalidMetadataSize:
218 case ErrorCode::kDownloadInvalidMetadataSignature:
219 case ErrorCode::kOmahaResponseInvalid:
220 case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
221 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
Kevin Cernekee2494e282016-03-29 18:03:53 -0700222 case ErrorCode::kNonCriticalUpdateInOOBE:
Alex Deymo38429cf2015-11-11 18:27:22 -0800223 case ErrorCode::kOmahaErrorInHTTPResponse:
224 case ErrorCode::kDownloadOperationHashMissingError:
225 case ErrorCode::kDownloadMetadataSignatureMissingError:
226 case ErrorCode::kOmahaUpdateDeferredForBackoff:
227 case ErrorCode::kPostinstallPowerwashError:
228 case ErrorCode::kUpdateCanceledByChannelChange:
229 case ErrorCode::kPostinstallFirmwareRONotUpdatable:
230 case ErrorCode::kUnsupportedMajorPayloadVersion:
231 case ErrorCode::kUnsupportedMinorPayloadVersion:
232 case ErrorCode::kOmahaRequestXMLHasEntityDecl:
233 case ErrorCode::kFilesystemVerifierError:
Alex Deymo1f19dcc2016-02-03 09:22:17 -0800234 case ErrorCode::kUserCanceled:
Weidong Guo421ff332017-04-17 10:08:38 -0700235 case ErrorCode::kOmahaUpdateIgnoredOverCellular:
Sen Jiang8e768e92017-06-28 17:13:19 -0700236 case ErrorCode::kPayloadTimestampError:
Sen Jiangfe522822017-10-31 15:14:11 -0700237 case ErrorCode::kUpdatedButNotActive:
Sen Jiang89e24c12018-03-22 18:05:44 -0700238 case ErrorCode::kNoUpdate:
Marton Hunyady199152d2018-05-07 19:08:48 +0200239 case ErrorCode::kRollbackNotPossible:
Amin Hassani80f4d4c2018-05-16 13:34:00 -0700240 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
Sen Jiang57f91802017-11-14 17:42:13 -0800241 case ErrorCode::kVerityCalculationError:
Yifan Hong46e37d42019-12-13 12:01:42 -0800242 case ErrorCode::kNotEnoughSpace:
Yifan Hong77279902019-12-17 16:38:21 -0800243 case ErrorCode::kDeviceCorrupted:
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700244 case ErrorCode::kPackageExcludedFromUpdate:
Alex Deymo38429cf2015-11-11 18:27:22 -0800245 break;
246
247 // Special flags. These can't happen (we mask them out above) but
248 // the compiler doesn't know that. Just break out so we can warn and
249 // return |kInputMalformed|.
250 case ErrorCode::kUmaReportedMax:
251 case ErrorCode::kOmahaRequestHTTPResponseBase:
252 case ErrorCode::kDevModeFlag:
253 case ErrorCode::kResumedFlag:
254 case ErrorCode::kTestImageFlag:
255 case ErrorCode::kTestOmahaUrlFlag:
256 case ErrorCode::kSpecialFlags:
257 LOG(ERROR) << "Unexpected error code " << base_code;
258 break;
259 }
260
261 return metrics::DownloadErrorCode::kInputMalformed;
262}
263
Sen Jiang255e22b2016-05-20 16:15:29 -0700264metrics::ConnectionType GetConnectionType(ConnectionType type,
265 ConnectionTethering tethering) {
Alex Deymo38429cf2015-11-11 18:27:22 -0800266 switch (type) {
Sen Jiang255e22b2016-05-20 16:15:29 -0700267 case ConnectionType::kUnknown:
Alex Deymo38429cf2015-11-11 18:27:22 -0800268 return metrics::ConnectionType::kUnknown;
269
Colin Howesc9e98d62018-09-18 10:35:20 -0700270 case ConnectionType::kDisconnected:
271 return metrics::ConnectionType::kDisconnected;
272
Sen Jiang255e22b2016-05-20 16:15:29 -0700273 case ConnectionType::kEthernet:
274 if (tethering == ConnectionTethering::kConfirmed)
Alex Deymo38429cf2015-11-11 18:27:22 -0800275 return metrics::ConnectionType::kTetheredEthernet;
276 else
277 return metrics::ConnectionType::kEthernet;
278
Sen Jiang255e22b2016-05-20 16:15:29 -0700279 case ConnectionType::kWifi:
280 if (tethering == ConnectionTethering::kConfirmed)
Alex Deymo38429cf2015-11-11 18:27:22 -0800281 return metrics::ConnectionType::kTetheredWifi;
282 else
283 return metrics::ConnectionType::kWifi;
284
Sen Jiang255e22b2016-05-20 16:15:29 -0700285 case ConnectionType::kCellular:
Alex Deymo38429cf2015-11-11 18:27:22 -0800286 return metrics::ConnectionType::kCellular;
287 }
288
289 LOG(ERROR) << "Unexpected network connection type: type="
290 << static_cast<int>(type)
291 << ", tethering=" << static_cast<int>(tethering);
292
293 return metrics::ConnectionType::kUnknown;
294}
295
Alex Deymoa2591792015-11-17 00:39:40 -0300296bool WallclockDurationHelper(SystemState* system_state,
297 const std::string& state_variable_key,
298 TimeDelta* out_duration) {
299 bool ret = false;
300
301 Time now = system_state->clock()->GetWallclockTime();
302 int64_t stored_value;
303 if (system_state->prefs()->GetInt64(state_variable_key, &stored_value)) {
304 Time stored_time = Time::FromInternalValue(stored_value);
305 if (stored_time > now) {
306 LOG(ERROR) << "Stored time-stamp used for " << state_variable_key
307 << " is in the future.";
308 } else {
309 *out_duration = now - stored_time;
310 ret = true;
311 }
312 }
313
314 if (!system_state->prefs()->SetInt64(state_variable_key,
315 now.ToInternalValue())) {
316 LOG(ERROR) << "Error storing time-stamp in " << state_variable_key;
317 }
318
319 return ret;
320}
321
322bool MonotonicDurationHelper(SystemState* system_state,
323 int64_t* storage,
324 TimeDelta* out_duration) {
325 bool ret = false;
326
327 Time now = system_state->clock()->GetMonotonicTime();
328 if (*storage != 0) {
329 Time stored_time = Time::FromInternalValue(*storage);
330 *out_duration = now - stored_time;
331 ret = true;
332 }
333 *storage = now.ToInternalValue();
334
335 return ret;
336}
337
Tianjie Xu90aaa102017-10-10 17:39:03 -0700338int64_t GetPersistedValue(const std::string& key, PrefsInterface* prefs) {
339 CHECK(prefs);
340 if (!prefs->Exists(key))
341 return 0;
342
343 int64_t stored_value;
344 if (!prefs->GetInt64(key, &stored_value))
345 return 0;
346
347 if (stored_value < 0) {
348 LOG(ERROR) << key << ": Invalid value (" << stored_value
349 << ") in persisted state. Defaulting to 0";
350 return 0;
351 }
352
353 return stored_value;
354}
355
356void SetNumReboots(int64_t num_reboots, PrefsInterface* prefs) {
357 CHECK(prefs);
358 prefs->SetInt64(kPrefsNumReboots, num_reboots);
359 LOG(INFO) << "Number of Reboots during current update attempt = "
360 << num_reboots;
361}
362
363void SetPayloadAttemptNumber(int64_t payload_attempt_number,
364 PrefsInterface* prefs) {
365 CHECK(prefs);
366 prefs->SetInt64(kPrefsPayloadAttemptNumber, payload_attempt_number);
367 LOG(INFO) << "Payload Attempt Number = " << payload_attempt_number;
368}
369
370void SetSystemUpdatedMarker(ClockInterface* clock, PrefsInterface* prefs) {
371 CHECK(prefs);
372 CHECK(clock);
373 Time update_finish_time = clock->GetMonotonicTime();
374 prefs->SetInt64(kPrefsSystemUpdatedMarker,
375 update_finish_time.ToInternalValue());
376 LOG(INFO) << "Updated Marker = " << utils::ToString(update_finish_time);
377}
378
379void SetUpdateTimestampStart(const Time& update_start_time,
380 PrefsInterface* prefs) {
381 CHECK(prefs);
382 prefs->SetInt64(kPrefsUpdateTimestampStart,
383 update_start_time.ToInternalValue());
Tianjie Xu2a0ea632018-08-06 12:59:23 -0700384 LOG(INFO) << "Update Monotonic Timestamp Start = "
Tianjie Xu90aaa102017-10-10 17:39:03 -0700385 << utils::ToString(update_start_time);
386}
387
Tianjie Xu2a0ea632018-08-06 12:59:23 -0700388void SetUpdateBootTimestampStart(const base::Time& update_start_boot_time,
389 PrefsInterface* prefs) {
390 CHECK(prefs);
391 prefs->SetInt64(kPrefsUpdateBootTimestampStart,
392 update_start_boot_time.ToInternalValue());
393 LOG(INFO) << "Update Boot Timestamp Start = "
394 << utils::ToString(update_start_boot_time);
395}
396
Tianjie Xu90aaa102017-10-10 17:39:03 -0700397bool LoadAndReportTimeToReboot(MetricsReporterInterface* metrics_reporter,
398 PrefsInterface* prefs,
399 ClockInterface* clock) {
400 CHECK(prefs);
401 CHECK(clock);
402 int64_t stored_value = GetPersistedValue(kPrefsSystemUpdatedMarker, prefs);
403 if (stored_value == 0)
404 return false;
405
406 Time system_updated_at = Time::FromInternalValue(stored_value);
407 base::TimeDelta time_to_reboot =
408 clock->GetMonotonicTime() - system_updated_at;
409 if (time_to_reboot.ToInternalValue() < 0) {
410 LOG(ERROR) << "time_to_reboot is negative - system_updated_at: "
411 << utils::ToString(system_updated_at);
412 return false;
413 }
414 metrics_reporter->ReportTimeToReboot(time_to_reboot.InMinutes());
415 return true;
416}
417
Alex Deymo38429cf2015-11-11 18:27:22 -0800418} // namespace metrics_utils
419} // namespace chromeos_update_engine