blob: 94a052011988045a29a2079944bf8e9814090643 [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
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
Sen Jiangfe522822017-10-31 15:14:11 -070041 case ErrorCode::kUpdatedButNotActive:
42 return metrics::AttemptResult::kUpdateSucceededNotActive;
43
Alex Deymo38429cf2015-11-11 18:27:22 -080044 case ErrorCode::kDownloadTransferError:
Amin Hassanid3d84212019-08-17 00:27:44 -070045 case ErrorCode::kInternalLibCurlError:
46 case ErrorCode::kUnresolvedHostError:
47 case ErrorCode::kUnresolvedHostRecovered:
Alex Deymo38429cf2015-11-11 18:27:22 -080048 return metrics::AttemptResult::kPayloadDownloadError;
49
50 case ErrorCode::kDownloadInvalidMetadataSize:
51 case ErrorCode::kDownloadInvalidMetadataMagicString:
52 case ErrorCode::kDownloadMetadataSignatureError:
53 case ErrorCode::kDownloadMetadataSignatureVerificationError:
54 case ErrorCode::kPayloadMismatchedType:
55 case ErrorCode::kUnsupportedMajorPayloadVersion:
56 case ErrorCode::kUnsupportedMinorPayloadVersion:
57 case ErrorCode::kDownloadNewPartitionInfoError:
58 case ErrorCode::kDownloadSignatureMissingInManifest:
59 case ErrorCode::kDownloadManifestParseError:
60 case ErrorCode::kDownloadOperationHashMissingError:
61 return metrics::AttemptResult::kMetadataMalformed;
62
63 case ErrorCode::kDownloadOperationHashMismatch:
64 case ErrorCode::kDownloadOperationHashVerificationError:
65 return metrics::AttemptResult::kOperationMalformed;
66
67 case ErrorCode::kDownloadOperationExecutionError:
68 case ErrorCode::kInstallDeviceOpenError:
69 case ErrorCode::kKernelDeviceOpenError:
70 case ErrorCode::kDownloadWriteError:
71 case ErrorCode::kFilesystemCopierError:
72 case ErrorCode::kFilesystemVerifierError:
Sen Jiang57f91802017-11-14 17:42:13 -080073 case ErrorCode::kVerityCalculationError:
Yifan Hong46e37d42019-12-13 12:01:42 -080074 case ErrorCode::kNotEnoughSpace:
Yifan Hong77279902019-12-17 16:38:21 -080075 case ErrorCode::kDeviceCorrupted:
Daniel Zhengeede4c82023-06-13 11:21:06 -070076 case ErrorCode::kOverlayfsenabledError:
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:
Kelvin Zhang8b1e0dc2020-10-26 12:27:53 -040098 case ErrorCode::kPostInstallMountError:
Alex Deymo38429cf2015-11-11 18:27:22 -080099 return metrics::AttemptResult::kPostInstallFailed;
100
Alex Deymo1f19dcc2016-02-03 09:22:17 -0800101 case ErrorCode::kUserCanceled:
102 return metrics::AttemptResult::kUpdateCanceled;
103
Alex Deymo38429cf2015-11-11 18:27:22 -0800104 // We should never get these errors in the update-attempt stage so
105 // return internal error if this happens.
106 case ErrorCode::kError:
107 case ErrorCode::kOmahaRequestXMLParseError:
108 case ErrorCode::kOmahaRequestError:
109 case ErrorCode::kOmahaResponseHandlerError:
110 case ErrorCode::kDownloadStateInitializationError:
111 case ErrorCode::kOmahaRequestEmptyResponseError:
112 case ErrorCode::kDownloadInvalidMetadataSignature:
113 case ErrorCode::kOmahaResponseInvalid:
114 case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
Alex Deymo38429cf2015-11-11 18:27:22 -0800115 case ErrorCode::kOmahaErrorInHTTPResponse:
116 case ErrorCode::kDownloadMetadataSignatureMissingError:
117 case ErrorCode::kOmahaUpdateDeferredForBackoff:
118 case ErrorCode::kPostinstallPowerwashError:
119 case ErrorCode::kUpdateCanceledByChannelChange:
120 case ErrorCode::kOmahaRequestXMLHasEntityDecl:
Weidong Guo421ff332017-04-17 10:08:38 -0700121 case ErrorCode::kOmahaUpdateIgnoredOverCellular:
Sen Jiang89e24c12018-03-22 18:05:44 -0700122 case ErrorCode::kNoUpdate:
Amin Hassani80f4d4c2018-05-16 13:34:00 -0700123 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700124 case ErrorCode::kPackageExcludedFromUpdate:
Alex Deymo38429cf2015-11-11 18:27:22 -0800125 return metrics::AttemptResult::kInternalError;
126
Andrewb57c16e2020-07-22 14:32:39 -0700127 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
128 case ErrorCode::kNonCriticalUpdateInOOBE:
129 return metrics::AttemptResult::kUpdateSkipped;
130
Alex Deymo38429cf2015-11-11 18:27:22 -0800131 // Special flags. These can't happen (we mask them out above) but
132 // the compiler doesn't know that. Just break out so we can warn and
133 // return |kInternalError|.
134 case ErrorCode::kUmaReportedMax:
135 case ErrorCode::kOmahaRequestHTTPResponseBase:
136 case ErrorCode::kDevModeFlag:
137 case ErrorCode::kResumedFlag:
138 case ErrorCode::kTestImageFlag:
139 case ErrorCode::kTestOmahaUrlFlag:
140 case ErrorCode::kSpecialFlags:
141 break;
142 }
143
144 LOG(ERROR) << "Unexpected error code " << base_code;
145 return metrics::AttemptResult::kInternalError;
146}
147
148metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) {
149 ErrorCode base_code = static_cast<ErrorCode>(
150 static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
151
152 if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
153 int http_status =
154 static_cast<int>(base_code) -
155 static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase);
156 if (http_status >= 200 && http_status <= 599) {
157 return static_cast<metrics::DownloadErrorCode>(
158 static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) +
159 http_status - 200);
160 } else if (http_status == 0) {
161 // The code is using HTTP Status 0 for "Unable to get http
162 // response code."
163 return metrics::DownloadErrorCode::kDownloadError;
164 }
165 LOG(WARNING) << "Unexpected HTTP status code " << http_status;
166 return metrics::DownloadErrorCode::kHttpStatusOther;
167 }
168
169 switch (base_code) {
170 // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide
171 // variety of errors (proxy errors, host not reachable, timeouts etc.).
172 //
173 // For now just map that to kDownloading. See http://crbug.com/355745
174 // for how we plan to add more detail in the future.
175 case ErrorCode::kDownloadTransferError:
176 return metrics::DownloadErrorCode::kDownloadError;
177
Amin Hassanid3d84212019-08-17 00:27:44 -0700178 case ErrorCode::kInternalLibCurlError:
179 return metrics::DownloadErrorCode::kInternalLibCurlError;
180 case ErrorCode::kUnresolvedHostError:
181 return metrics::DownloadErrorCode::kUnresolvedHostError;
182 case ErrorCode::kUnresolvedHostRecovered:
183 return metrics::DownloadErrorCode::kUnresolvedHostRecovered;
184
Alex Deymo38429cf2015-11-11 18:27:22 -0800185 // All of these error codes are not related to downloading so break
186 // out so we can warn and return InputMalformed.
187 case ErrorCode::kSuccess:
188 case ErrorCode::kError:
189 case ErrorCode::kOmahaRequestError:
190 case ErrorCode::kOmahaResponseHandlerError:
191 case ErrorCode::kFilesystemCopierError:
192 case ErrorCode::kPostinstallRunnerError:
Kelvin Zhang8b1e0dc2020-10-26 12:27:53 -0400193 case ErrorCode::kPostInstallMountError:
Daniel Zhengeede4c82023-06-13 11:21:06 -0700194 case ErrorCode::kOverlayfsenabledError:
Alex Deymo38429cf2015-11-11 18:27:22 -0800195 case ErrorCode::kPayloadMismatchedType:
196 case ErrorCode::kInstallDeviceOpenError:
197 case ErrorCode::kKernelDeviceOpenError:
198 case ErrorCode::kPayloadHashMismatchError:
199 case ErrorCode::kPayloadSizeMismatchError:
200 case ErrorCode::kDownloadPayloadVerificationError:
201 case ErrorCode::kDownloadNewPartitionInfoError:
202 case ErrorCode::kDownloadWriteError:
203 case ErrorCode::kNewRootfsVerificationError:
204 case ErrorCode::kNewKernelVerificationError:
205 case ErrorCode::kSignedDeltaPayloadExpectedError:
206 case ErrorCode::kDownloadPayloadPubKeyVerificationError:
207 case ErrorCode::kPostinstallBootedFromFirmwareB:
208 case ErrorCode::kDownloadStateInitializationError:
209 case ErrorCode::kDownloadInvalidMetadataMagicString:
210 case ErrorCode::kDownloadSignatureMissingInManifest:
211 case ErrorCode::kDownloadManifestParseError:
212 case ErrorCode::kDownloadMetadataSignatureError:
213 case ErrorCode::kDownloadMetadataSignatureVerificationError:
214 case ErrorCode::kDownloadMetadataSignatureMismatch:
215 case ErrorCode::kDownloadOperationHashVerificationError:
216 case ErrorCode::kDownloadOperationExecutionError:
217 case ErrorCode::kDownloadOperationHashMismatch:
218 case ErrorCode::kOmahaRequestEmptyResponseError:
219 case ErrorCode::kOmahaRequestXMLParseError:
220 case ErrorCode::kDownloadInvalidMetadataSize:
221 case ErrorCode::kDownloadInvalidMetadataSignature:
222 case ErrorCode::kOmahaResponseInvalid:
223 case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
224 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
Kevin Cernekee2494e282016-03-29 18:03:53 -0700225 case ErrorCode::kNonCriticalUpdateInOOBE:
Alex Deymo38429cf2015-11-11 18:27:22 -0800226 case ErrorCode::kOmahaErrorInHTTPResponse:
227 case ErrorCode::kDownloadOperationHashMissingError:
228 case ErrorCode::kDownloadMetadataSignatureMissingError:
229 case ErrorCode::kOmahaUpdateDeferredForBackoff:
230 case ErrorCode::kPostinstallPowerwashError:
231 case ErrorCode::kUpdateCanceledByChannelChange:
232 case ErrorCode::kPostinstallFirmwareRONotUpdatable:
233 case ErrorCode::kUnsupportedMajorPayloadVersion:
234 case ErrorCode::kUnsupportedMinorPayloadVersion:
235 case ErrorCode::kOmahaRequestXMLHasEntityDecl:
236 case ErrorCode::kFilesystemVerifierError:
Alex Deymo1f19dcc2016-02-03 09:22:17 -0800237 case ErrorCode::kUserCanceled:
Weidong Guo421ff332017-04-17 10:08:38 -0700238 case ErrorCode::kOmahaUpdateIgnoredOverCellular:
Sen Jiang8e768e92017-06-28 17:13:19 -0700239 case ErrorCode::kPayloadTimestampError:
Sen Jiangfe522822017-10-31 15:14:11 -0700240 case ErrorCode::kUpdatedButNotActive:
Sen Jiang89e24c12018-03-22 18:05:44 -0700241 case ErrorCode::kNoUpdate:
Marton Hunyady199152d2018-05-07 19:08:48 +0200242 case ErrorCode::kRollbackNotPossible:
Amin Hassani80f4d4c2018-05-16 13:34:00 -0700243 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
Sen Jiang57f91802017-11-14 17:42:13 -0800244 case ErrorCode::kVerityCalculationError:
Yifan Hong46e37d42019-12-13 12:01:42 -0800245 case ErrorCode::kNotEnoughSpace:
Yifan Hong77279902019-12-17 16:38:21 -0800246 case ErrorCode::kDeviceCorrupted:
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700247 case ErrorCode::kPackageExcludedFromUpdate:
Alex Deymo38429cf2015-11-11 18:27:22 -0800248 break;
249
250 // Special flags. These can't happen (we mask them out above) but
251 // the compiler doesn't know that. Just break out so we can warn and
252 // return |kInputMalformed|.
253 case ErrorCode::kUmaReportedMax:
254 case ErrorCode::kOmahaRequestHTTPResponseBase:
255 case ErrorCode::kDevModeFlag:
256 case ErrorCode::kResumedFlag:
257 case ErrorCode::kTestImageFlag:
258 case ErrorCode::kTestOmahaUrlFlag:
259 case ErrorCode::kSpecialFlags:
260 LOG(ERROR) << "Unexpected error code " << base_code;
261 break;
262 }
263
264 return metrics::DownloadErrorCode::kInputMalformed;
265}
266
Sen Jiang255e22b2016-05-20 16:15:29 -0700267metrics::ConnectionType GetConnectionType(ConnectionType type,
268 ConnectionTethering tethering) {
Alex Deymo38429cf2015-11-11 18:27:22 -0800269 switch (type) {
Sen Jiang255e22b2016-05-20 16:15:29 -0700270 case ConnectionType::kUnknown:
Alex Deymo38429cf2015-11-11 18:27:22 -0800271 return metrics::ConnectionType::kUnknown;
272
Colin Howesc9e98d62018-09-18 10:35:20 -0700273 case ConnectionType::kDisconnected:
274 return metrics::ConnectionType::kDisconnected;
275
Sen Jiang255e22b2016-05-20 16:15:29 -0700276 case ConnectionType::kEthernet:
277 if (tethering == ConnectionTethering::kConfirmed)
Alex Deymo38429cf2015-11-11 18:27:22 -0800278 return metrics::ConnectionType::kTetheredEthernet;
279 else
280 return metrics::ConnectionType::kEthernet;
281
Sen Jiang255e22b2016-05-20 16:15:29 -0700282 case ConnectionType::kWifi:
283 if (tethering == ConnectionTethering::kConfirmed)
Alex Deymo38429cf2015-11-11 18:27:22 -0800284 return metrics::ConnectionType::kTetheredWifi;
285 else
286 return metrics::ConnectionType::kWifi;
287
Sen Jiang255e22b2016-05-20 16:15:29 -0700288 case ConnectionType::kCellular:
Alex Deymo38429cf2015-11-11 18:27:22 -0800289 return metrics::ConnectionType::kCellular;
290 }
291
292 LOG(ERROR) << "Unexpected network connection type: type="
293 << static_cast<int>(type)
294 << ", tethering=" << static_cast<int>(tethering);
295
296 return metrics::ConnectionType::kUnknown;
297}
298
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400299int64_t GetPersistedValue(std::string_view key, PrefsInterface* prefs) {
Tianjie Xu90aaa102017-10-10 17:39:03 -0700300 CHECK(prefs);
301 if (!prefs->Exists(key))
302 return 0;
303
304 int64_t stored_value;
305 if (!prefs->GetInt64(key, &stored_value))
306 return 0;
307
308 if (stored_value < 0) {
309 LOG(ERROR) << key << ": Invalid value (" << stored_value
310 << ") in persisted state. Defaulting to 0";
311 return 0;
312 }
313
314 return stored_value;
315}
316
317void SetNumReboots(int64_t num_reboots, PrefsInterface* prefs) {
318 CHECK(prefs);
319 prefs->SetInt64(kPrefsNumReboots, num_reboots);
320 LOG(INFO) << "Number of Reboots during current update attempt = "
321 << num_reboots;
322}
323
324void SetPayloadAttemptNumber(int64_t payload_attempt_number,
325 PrefsInterface* prefs) {
326 CHECK(prefs);
327 prefs->SetInt64(kPrefsPayloadAttemptNumber, payload_attempt_number);
328 LOG(INFO) << "Payload Attempt Number = " << payload_attempt_number;
329}
330
331void SetSystemUpdatedMarker(ClockInterface* clock, PrefsInterface* prefs) {
332 CHECK(prefs);
333 CHECK(clock);
334 Time update_finish_time = clock->GetMonotonicTime();
335 prefs->SetInt64(kPrefsSystemUpdatedMarker,
336 update_finish_time.ToInternalValue());
337 LOG(INFO) << "Updated Marker = " << utils::ToString(update_finish_time);
338}
339
340void SetUpdateTimestampStart(const Time& update_start_time,
341 PrefsInterface* prefs) {
342 CHECK(prefs);
343 prefs->SetInt64(kPrefsUpdateTimestampStart,
344 update_start_time.ToInternalValue());
Tianjie Xu2a0ea632018-08-06 12:59:23 -0700345 LOG(INFO) << "Update Monotonic Timestamp Start = "
Tianjie Xu90aaa102017-10-10 17:39:03 -0700346 << utils::ToString(update_start_time);
347}
348
Tianjie Xu2a0ea632018-08-06 12:59:23 -0700349void SetUpdateBootTimestampStart(const base::Time& update_start_boot_time,
350 PrefsInterface* prefs) {
351 CHECK(prefs);
352 prefs->SetInt64(kPrefsUpdateBootTimestampStart,
353 update_start_boot_time.ToInternalValue());
354 LOG(INFO) << "Update Boot Timestamp Start = "
355 << utils::ToString(update_start_boot_time);
356}
357
Tianjie Xu90aaa102017-10-10 17:39:03 -0700358bool LoadAndReportTimeToReboot(MetricsReporterInterface* metrics_reporter,
359 PrefsInterface* prefs,
360 ClockInterface* clock) {
361 CHECK(prefs);
362 CHECK(clock);
363 int64_t stored_value = GetPersistedValue(kPrefsSystemUpdatedMarker, prefs);
364 if (stored_value == 0)
365 return false;
366
367 Time system_updated_at = Time::FromInternalValue(stored_value);
Kelvin Zhang1f690a42022-02-22 09:36:39 -0800368 const auto current_time = clock->GetMonotonicTime();
369 TimeDelta time_to_reboot = current_time - system_updated_at;
Tianjie Xu90aaa102017-10-10 17:39:03 -0700370 if (time_to_reboot.ToInternalValue() < 0) {
Kelvin Zhang1f690a42022-02-22 09:36:39 -0800371 LOG(WARNING) << "time_to_reboot is negative - system_updated_at: "
Daniel Zhengeede4c82023-06-13 11:21:06 -0700372 << utils::ToString(system_updated_at)
373 << " current time: " << utils::ToString(current_time);
Tianjie Xu90aaa102017-10-10 17:39:03 -0700374 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