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