blob: 070626a491ae95f23af2ab5e87cc1a9f0792903d [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:
46 return metrics::AttemptResult::kPayloadDownloadError;
47
48 case ErrorCode::kDownloadInvalidMetadataSize:
49 case ErrorCode::kDownloadInvalidMetadataMagicString:
50 case ErrorCode::kDownloadMetadataSignatureError:
51 case ErrorCode::kDownloadMetadataSignatureVerificationError:
52 case ErrorCode::kPayloadMismatchedType:
53 case ErrorCode::kUnsupportedMajorPayloadVersion:
54 case ErrorCode::kUnsupportedMinorPayloadVersion:
55 case ErrorCode::kDownloadNewPartitionInfoError:
56 case ErrorCode::kDownloadSignatureMissingInManifest:
57 case ErrorCode::kDownloadManifestParseError:
58 case ErrorCode::kDownloadOperationHashMissingError:
59 return metrics::AttemptResult::kMetadataMalformed;
60
61 case ErrorCode::kDownloadOperationHashMismatch:
62 case ErrorCode::kDownloadOperationHashVerificationError:
63 return metrics::AttemptResult::kOperationMalformed;
64
65 case ErrorCode::kDownloadOperationExecutionError:
66 case ErrorCode::kInstallDeviceOpenError:
67 case ErrorCode::kKernelDeviceOpenError:
68 case ErrorCode::kDownloadWriteError:
69 case ErrorCode::kFilesystemCopierError:
70 case ErrorCode::kFilesystemVerifierError:
Sen Jiang57f91802017-11-14 17:42:13 -080071 case ErrorCode::kVerityCalculationError:
Alex Deymo38429cf2015-11-11 18:27:22 -080072 return metrics::AttemptResult::kOperationExecutionError;
73
74 case ErrorCode::kDownloadMetadataSignatureMismatch:
75 return metrics::AttemptResult::kMetadataVerificationFailed;
76
77 case ErrorCode::kPayloadSizeMismatchError:
78 case ErrorCode::kPayloadHashMismatchError:
79 case ErrorCode::kDownloadPayloadVerificationError:
80 case ErrorCode::kSignedDeltaPayloadExpectedError:
81 case ErrorCode::kDownloadPayloadPubKeyVerificationError:
Sen Jiang8e768e92017-06-28 17:13:19 -070082 case ErrorCode::kPayloadTimestampError:
Alex Deymo38429cf2015-11-11 18:27:22 -080083 return metrics::AttemptResult::kPayloadVerificationFailed;
84
85 case ErrorCode::kNewRootfsVerificationError:
86 case ErrorCode::kNewKernelVerificationError:
Marton Hunyady199152d2018-05-07 19:08:48 +020087 case ErrorCode::kRollbackNotPossible:
Alex Deymo38429cf2015-11-11 18:27:22 -080088 return metrics::AttemptResult::kVerificationFailed;
89
90 case ErrorCode::kPostinstallRunnerError:
91 case ErrorCode::kPostinstallBootedFromFirmwareB:
92 case ErrorCode::kPostinstallFirmwareRONotUpdatable:
93 return metrics::AttemptResult::kPostInstallFailed;
94
Alex Deymo1f19dcc2016-02-03 09:22:17 -080095 case ErrorCode::kUserCanceled:
96 return metrics::AttemptResult::kUpdateCanceled;
97
Alex Deymo38429cf2015-11-11 18:27:22 -080098 // We should never get these errors in the update-attempt stage so
99 // return internal error if this happens.
100 case ErrorCode::kError:
101 case ErrorCode::kOmahaRequestXMLParseError:
102 case ErrorCode::kOmahaRequestError:
103 case ErrorCode::kOmahaResponseHandlerError:
104 case ErrorCode::kDownloadStateInitializationError:
105 case ErrorCode::kOmahaRequestEmptyResponseError:
106 case ErrorCode::kDownloadInvalidMetadataSignature:
107 case ErrorCode::kOmahaResponseInvalid:
108 case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
Kevin Cernekee2494e282016-03-29 18:03:53 -0700109 // TODO(deymo): The next two items belong in their own category; they
110 // should not be counted as internal errors. b/27112092
Alex Deymo38429cf2015-11-11 18:27:22 -0800111 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
Kevin Cernekee2494e282016-03-29 18:03:53 -0700112 case ErrorCode::kNonCriticalUpdateInOOBE:
Alex Deymo38429cf2015-11-11 18:27:22 -0800113 case ErrorCode::kOmahaErrorInHTTPResponse:
114 case ErrorCode::kDownloadMetadataSignatureMissingError:
115 case ErrorCode::kOmahaUpdateDeferredForBackoff:
116 case ErrorCode::kPostinstallPowerwashError:
117 case ErrorCode::kUpdateCanceledByChannelChange:
118 case ErrorCode::kOmahaRequestXMLHasEntityDecl:
Weidong Guo421ff332017-04-17 10:08:38 -0700119 case ErrorCode::kOmahaUpdateIgnoredOverCellular:
Sen Jiang89e24c12018-03-22 18:05:44 -0700120 case ErrorCode::kNoUpdate:
Amin Hassani80f4d4c2018-05-16 13:34:00 -0700121 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
Alex Deymo38429cf2015-11-11 18:27:22 -0800122 return metrics::AttemptResult::kInternalError;
123
124 // Special flags. These can't happen (we mask them out above) but
125 // the compiler doesn't know that. Just break out so we can warn and
126 // return |kInternalError|.
127 case ErrorCode::kUmaReportedMax:
128 case ErrorCode::kOmahaRequestHTTPResponseBase:
129 case ErrorCode::kDevModeFlag:
130 case ErrorCode::kResumedFlag:
131 case ErrorCode::kTestImageFlag:
132 case ErrorCode::kTestOmahaUrlFlag:
133 case ErrorCode::kSpecialFlags:
134 break;
135 }
136
137 LOG(ERROR) << "Unexpected error code " << base_code;
138 return metrics::AttemptResult::kInternalError;
139}
140
141metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) {
142 ErrorCode base_code = static_cast<ErrorCode>(
143 static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
144
145 if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
146 int http_status =
147 static_cast<int>(base_code) -
148 static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase);
149 if (http_status >= 200 && http_status <= 599) {
150 return static_cast<metrics::DownloadErrorCode>(
151 static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) +
152 http_status - 200);
153 } else if (http_status == 0) {
154 // The code is using HTTP Status 0 for "Unable to get http
155 // response code."
156 return metrics::DownloadErrorCode::kDownloadError;
157 }
158 LOG(WARNING) << "Unexpected HTTP status code " << http_status;
159 return metrics::DownloadErrorCode::kHttpStatusOther;
160 }
161
162 switch (base_code) {
163 // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide
164 // variety of errors (proxy errors, host not reachable, timeouts etc.).
165 //
166 // For now just map that to kDownloading. See http://crbug.com/355745
167 // for how we plan to add more detail in the future.
168 case ErrorCode::kDownloadTransferError:
169 return metrics::DownloadErrorCode::kDownloadError;
170
171 // All of these error codes are not related to downloading so break
172 // out so we can warn and return InputMalformed.
173 case ErrorCode::kSuccess:
174 case ErrorCode::kError:
175 case ErrorCode::kOmahaRequestError:
176 case ErrorCode::kOmahaResponseHandlerError:
177 case ErrorCode::kFilesystemCopierError:
178 case ErrorCode::kPostinstallRunnerError:
179 case ErrorCode::kPayloadMismatchedType:
180 case ErrorCode::kInstallDeviceOpenError:
181 case ErrorCode::kKernelDeviceOpenError:
182 case ErrorCode::kPayloadHashMismatchError:
183 case ErrorCode::kPayloadSizeMismatchError:
184 case ErrorCode::kDownloadPayloadVerificationError:
185 case ErrorCode::kDownloadNewPartitionInfoError:
186 case ErrorCode::kDownloadWriteError:
187 case ErrorCode::kNewRootfsVerificationError:
188 case ErrorCode::kNewKernelVerificationError:
189 case ErrorCode::kSignedDeltaPayloadExpectedError:
190 case ErrorCode::kDownloadPayloadPubKeyVerificationError:
191 case ErrorCode::kPostinstallBootedFromFirmwareB:
192 case ErrorCode::kDownloadStateInitializationError:
193 case ErrorCode::kDownloadInvalidMetadataMagicString:
194 case ErrorCode::kDownloadSignatureMissingInManifest:
195 case ErrorCode::kDownloadManifestParseError:
196 case ErrorCode::kDownloadMetadataSignatureError:
197 case ErrorCode::kDownloadMetadataSignatureVerificationError:
198 case ErrorCode::kDownloadMetadataSignatureMismatch:
199 case ErrorCode::kDownloadOperationHashVerificationError:
200 case ErrorCode::kDownloadOperationExecutionError:
201 case ErrorCode::kDownloadOperationHashMismatch:
202 case ErrorCode::kOmahaRequestEmptyResponseError:
203 case ErrorCode::kOmahaRequestXMLParseError:
204 case ErrorCode::kDownloadInvalidMetadataSize:
205 case ErrorCode::kDownloadInvalidMetadataSignature:
206 case ErrorCode::kOmahaResponseInvalid:
207 case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
208 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
Kevin Cernekee2494e282016-03-29 18:03:53 -0700209 case ErrorCode::kNonCriticalUpdateInOOBE:
Alex Deymo38429cf2015-11-11 18:27:22 -0800210 case ErrorCode::kOmahaErrorInHTTPResponse:
211 case ErrorCode::kDownloadOperationHashMissingError:
212 case ErrorCode::kDownloadMetadataSignatureMissingError:
213 case ErrorCode::kOmahaUpdateDeferredForBackoff:
214 case ErrorCode::kPostinstallPowerwashError:
215 case ErrorCode::kUpdateCanceledByChannelChange:
216 case ErrorCode::kPostinstallFirmwareRONotUpdatable:
217 case ErrorCode::kUnsupportedMajorPayloadVersion:
218 case ErrorCode::kUnsupportedMinorPayloadVersion:
219 case ErrorCode::kOmahaRequestXMLHasEntityDecl:
220 case ErrorCode::kFilesystemVerifierError:
Alex Deymo1f19dcc2016-02-03 09:22:17 -0800221 case ErrorCode::kUserCanceled:
Weidong Guo421ff332017-04-17 10:08:38 -0700222 case ErrorCode::kOmahaUpdateIgnoredOverCellular:
Sen Jiang8e768e92017-06-28 17:13:19 -0700223 case ErrorCode::kPayloadTimestampError:
Sen Jiangfe522822017-10-31 15:14:11 -0700224 case ErrorCode::kUpdatedButNotActive:
Sen Jiang89e24c12018-03-22 18:05:44 -0700225 case ErrorCode::kNoUpdate:
Marton Hunyady199152d2018-05-07 19:08:48 +0200226 case ErrorCode::kRollbackNotPossible:
Amin Hassani80f4d4c2018-05-16 13:34:00 -0700227 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
Sen Jiang57f91802017-11-14 17:42:13 -0800228 case ErrorCode::kVerityCalculationError:
Alex Deymo38429cf2015-11-11 18:27:22 -0800229 break;
230
231 // Special flags. These can't happen (we mask them out above) but
232 // the compiler doesn't know that. Just break out so we can warn and
233 // return |kInputMalformed|.
234 case ErrorCode::kUmaReportedMax:
235 case ErrorCode::kOmahaRequestHTTPResponseBase:
236 case ErrorCode::kDevModeFlag:
237 case ErrorCode::kResumedFlag:
238 case ErrorCode::kTestImageFlag:
239 case ErrorCode::kTestOmahaUrlFlag:
240 case ErrorCode::kSpecialFlags:
241 LOG(ERROR) << "Unexpected error code " << base_code;
242 break;
243 }
244
245 return metrics::DownloadErrorCode::kInputMalformed;
246}
247
Sen Jiang255e22b2016-05-20 16:15:29 -0700248metrics::ConnectionType GetConnectionType(ConnectionType type,
249 ConnectionTethering tethering) {
Alex Deymo38429cf2015-11-11 18:27:22 -0800250 switch (type) {
Sen Jiang255e22b2016-05-20 16:15:29 -0700251 case ConnectionType::kUnknown:
Alex Deymo38429cf2015-11-11 18:27:22 -0800252 return metrics::ConnectionType::kUnknown;
253
Colin Howesc9e98d62018-09-18 10:35:20 -0700254 case ConnectionType::kDisconnected:
255 return metrics::ConnectionType::kDisconnected;
256
Sen Jiang255e22b2016-05-20 16:15:29 -0700257 case ConnectionType::kEthernet:
258 if (tethering == ConnectionTethering::kConfirmed)
Alex Deymo38429cf2015-11-11 18:27:22 -0800259 return metrics::ConnectionType::kTetheredEthernet;
260 else
261 return metrics::ConnectionType::kEthernet;
262
Sen Jiang255e22b2016-05-20 16:15:29 -0700263 case ConnectionType::kWifi:
264 if (tethering == ConnectionTethering::kConfirmed)
Alex Deymo38429cf2015-11-11 18:27:22 -0800265 return metrics::ConnectionType::kTetheredWifi;
266 else
267 return metrics::ConnectionType::kWifi;
268
Sen Jiang255e22b2016-05-20 16:15:29 -0700269 case ConnectionType::kWimax:
Alex Deymo38429cf2015-11-11 18:27:22 -0800270 return metrics::ConnectionType::kWimax;
271
Sen Jiang255e22b2016-05-20 16:15:29 -0700272 case ConnectionType::kBluetooth:
Alex Deymo38429cf2015-11-11 18:27:22 -0800273 return metrics::ConnectionType::kBluetooth;
274
Sen Jiang255e22b2016-05-20 16:15:29 -0700275 case ConnectionType::kCellular:
Alex Deymo38429cf2015-11-11 18:27:22 -0800276 return metrics::ConnectionType::kCellular;
277 }
278
279 LOG(ERROR) << "Unexpected network connection type: type="
280 << static_cast<int>(type)
281 << ", tethering=" << static_cast<int>(tethering);
282
283 return metrics::ConnectionType::kUnknown;
284}
285
Alex Deymoa2591792015-11-17 00:39:40 -0300286bool WallclockDurationHelper(SystemState* system_state,
287 const std::string& state_variable_key,
288 TimeDelta* out_duration) {
289 bool ret = false;
290
291 Time now = system_state->clock()->GetWallclockTime();
292 int64_t stored_value;
293 if (system_state->prefs()->GetInt64(state_variable_key, &stored_value)) {
294 Time stored_time = Time::FromInternalValue(stored_value);
295 if (stored_time > now) {
296 LOG(ERROR) << "Stored time-stamp used for " << state_variable_key
297 << " is in the future.";
298 } else {
299 *out_duration = now - stored_time;
300 ret = true;
301 }
302 }
303
304 if (!system_state->prefs()->SetInt64(state_variable_key,
305 now.ToInternalValue())) {
306 LOG(ERROR) << "Error storing time-stamp in " << state_variable_key;
307 }
308
309 return ret;
310}
311
312bool MonotonicDurationHelper(SystemState* system_state,
313 int64_t* storage,
314 TimeDelta* out_duration) {
315 bool ret = false;
316
317 Time now = system_state->clock()->GetMonotonicTime();
318 if (*storage != 0) {
319 Time stored_time = Time::FromInternalValue(*storage);
320 *out_duration = now - stored_time;
321 ret = true;
322 }
323 *storage = now.ToInternalValue();
324
325 return ret;
326}
327
Tianjie Xu90aaa102017-10-10 17:39:03 -0700328int64_t GetPersistedValue(const std::string& key, PrefsInterface* prefs) {
329 CHECK(prefs);
330 if (!prefs->Exists(key))
331 return 0;
332
333 int64_t stored_value;
334 if (!prefs->GetInt64(key, &stored_value))
335 return 0;
336
337 if (stored_value < 0) {
338 LOG(ERROR) << key << ": Invalid value (" << stored_value
339 << ") in persisted state. Defaulting to 0";
340 return 0;
341 }
342
343 return stored_value;
344}
345
346void SetNumReboots(int64_t num_reboots, PrefsInterface* prefs) {
347 CHECK(prefs);
348 prefs->SetInt64(kPrefsNumReboots, num_reboots);
349 LOG(INFO) << "Number of Reboots during current update attempt = "
350 << num_reboots;
351}
352
353void SetPayloadAttemptNumber(int64_t payload_attempt_number,
354 PrefsInterface* prefs) {
355 CHECK(prefs);
356 prefs->SetInt64(kPrefsPayloadAttemptNumber, payload_attempt_number);
357 LOG(INFO) << "Payload Attempt Number = " << payload_attempt_number;
358}
359
360void SetSystemUpdatedMarker(ClockInterface* clock, PrefsInterface* prefs) {
361 CHECK(prefs);
362 CHECK(clock);
363 Time update_finish_time = clock->GetMonotonicTime();
364 prefs->SetInt64(kPrefsSystemUpdatedMarker,
365 update_finish_time.ToInternalValue());
366 LOG(INFO) << "Updated Marker = " << utils::ToString(update_finish_time);
367}
368
369void SetUpdateTimestampStart(const Time& update_start_time,
370 PrefsInterface* prefs) {
371 CHECK(prefs);
372 prefs->SetInt64(kPrefsUpdateTimestampStart,
373 update_start_time.ToInternalValue());
Tianjie Xu2a0ea632018-08-06 12:59:23 -0700374 LOG(INFO) << "Update Monotonic Timestamp Start = "
Tianjie Xu90aaa102017-10-10 17:39:03 -0700375 << utils::ToString(update_start_time);
376}
377
Tianjie Xu2a0ea632018-08-06 12:59:23 -0700378void SetUpdateBootTimestampStart(const base::Time& update_start_boot_time,
379 PrefsInterface* prefs) {
380 CHECK(prefs);
381 prefs->SetInt64(kPrefsUpdateBootTimestampStart,
382 update_start_boot_time.ToInternalValue());
383 LOG(INFO) << "Update Boot Timestamp Start = "
384 << utils::ToString(update_start_boot_time);
385}
386
Tianjie Xu90aaa102017-10-10 17:39:03 -0700387bool LoadAndReportTimeToReboot(MetricsReporterInterface* metrics_reporter,
388 PrefsInterface* prefs,
389 ClockInterface* clock) {
390 CHECK(prefs);
391 CHECK(clock);
392 int64_t stored_value = GetPersistedValue(kPrefsSystemUpdatedMarker, prefs);
393 if (stored_value == 0)
394 return false;
395
396 Time system_updated_at = Time::FromInternalValue(stored_value);
397 base::TimeDelta time_to_reboot =
398 clock->GetMonotonicTime() - system_updated_at;
399 if (time_to_reboot.ToInternalValue() < 0) {
400 LOG(ERROR) << "time_to_reboot is negative - system_updated_at: "
401 << utils::ToString(system_updated_at);
402 return false;
403 }
404 metrics_reporter->ReportTimeToReboot(time_to_reboot.InMinutes());
405 return true;
406}
407
Alex Deymo38429cf2015-11-11 18:27:22 -0800408} // namespace metrics_utils
409} // namespace chromeos_update_engine