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