1 //
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
19 #include <string>
20
21 #include <base/time/time.h>
22
23 #include "update_engine/common/clock_interface.h"
24 #include "update_engine/common/constants.h"
25 #include "update_engine/common/utils.h"
26
27 using base::Time;
28 using base::TimeDelta;
29
30 namespace chromeos_update_engine {
31 namespace metrics_utils {
32
GetAttemptResult(ErrorCode code)33 metrics::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
41 case ErrorCode::kUpdatedButNotActive:
42 return metrics::AttemptResult::kUpdateSucceededNotActive;
43
44 case ErrorCode::kDownloadTransferError:
45 case ErrorCode::kInternalLibCurlError:
46 case ErrorCode::kUnresolvedHostError:
47 case ErrorCode::kUnresolvedHostRecovered:
48 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:
73 case ErrorCode::kVerityCalculationError:
74 case ErrorCode::kNotEnoughSpace:
75 case ErrorCode::kDeviceCorrupted:
76 case ErrorCode::kOverlayfsenabledError:
77 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:
87 case ErrorCode::kPayloadTimestampError:
88 return metrics::AttemptResult::kPayloadVerificationFailed;
89
90 case ErrorCode::kNewRootfsVerificationError:
91 case ErrorCode::kNewKernelVerificationError:
92 case ErrorCode::kRollbackNotPossible:
93 return metrics::AttemptResult::kVerificationFailed;
94
95 case ErrorCode::kPostinstallRunnerError:
96 case ErrorCode::kPostinstallBootedFromFirmwareB:
97 case ErrorCode::kPostinstallFirmwareRONotUpdatable:
98 case ErrorCode::kPostInstallMountError:
99 return metrics::AttemptResult::kPostInstallFailed;
100
101 case ErrorCode::kUserCanceled:
102 return metrics::AttemptResult::kUpdateCanceled;
103
104 // 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:
115 case ErrorCode::kOmahaErrorInHTTPResponse:
116 case ErrorCode::kDownloadMetadataSignatureMissingError:
117 case ErrorCode::kOmahaUpdateDeferredForBackoff:
118 case ErrorCode::kPostinstallPowerwashError:
119 case ErrorCode::kUpdateCanceledByChannelChange:
120 case ErrorCode::kOmahaRequestXMLHasEntityDecl:
121 case ErrorCode::kOmahaUpdateIgnoredOverCellular:
122 case ErrorCode::kNoUpdate:
123 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
124 case ErrorCode::kPackageExcludedFromUpdate:
125 return metrics::AttemptResult::kInternalError;
126
127 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
128 case ErrorCode::kNonCriticalUpdateInOOBE:
129 return metrics::AttemptResult::kUpdateSkipped;
130
131 // 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 case ErrorCode::kUpdateProcessing:
142 case ErrorCode::kUpdateAlreadyInstalled:
143 break;
144 }
145
146 LOG(ERROR) << "Unexpected error code " << base_code;
147 return metrics::AttemptResult::kInternalError;
148 }
149
GetDownloadErrorCode(ErrorCode code)150 metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) {
151 ErrorCode base_code = static_cast<ErrorCode>(
152 static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
153
154 if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
155 int http_status =
156 static_cast<int>(base_code) -
157 static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase);
158 if (http_status >= 200 && http_status <= 599) {
159 return static_cast<metrics::DownloadErrorCode>(
160 static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) +
161 http_status - 200);
162 } else if (http_status == 0) {
163 // The code is using HTTP Status 0 for "Unable to get http
164 // response code."
165 return metrics::DownloadErrorCode::kDownloadError;
166 }
167 LOG(WARNING) << "Unexpected HTTP status code " << http_status;
168 return metrics::DownloadErrorCode::kHttpStatusOther;
169 }
170
171 switch (base_code) {
172 // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide
173 // variety of errors (proxy errors, host not reachable, timeouts etc.).
174 //
175 // For now just map that to kDownloading. See http://crbug.com/355745
176 // for how we plan to add more detail in the future.
177 case ErrorCode::kDownloadTransferError:
178 return metrics::DownloadErrorCode::kDownloadError;
179
180 case ErrorCode::kInternalLibCurlError:
181 return metrics::DownloadErrorCode::kInternalLibCurlError;
182 case ErrorCode::kUnresolvedHostError:
183 return metrics::DownloadErrorCode::kUnresolvedHostError;
184 case ErrorCode::kUnresolvedHostRecovered:
185 return metrics::DownloadErrorCode::kUnresolvedHostRecovered;
186
187 // All of these error codes are not related to downloading so break
188 // out so we can warn and return InputMalformed.
189 case ErrorCode::kSuccess:
190 case ErrorCode::kError:
191 case ErrorCode::kOmahaRequestError:
192 case ErrorCode::kOmahaResponseHandlerError:
193 case ErrorCode::kFilesystemCopierError:
194 case ErrorCode::kPostinstallRunnerError:
195 case ErrorCode::kPostInstallMountError:
196 case ErrorCode::kOverlayfsenabledError:
197 case ErrorCode::kPayloadMismatchedType:
198 case ErrorCode::kInstallDeviceOpenError:
199 case ErrorCode::kKernelDeviceOpenError:
200 case ErrorCode::kPayloadHashMismatchError:
201 case ErrorCode::kPayloadSizeMismatchError:
202 case ErrorCode::kDownloadPayloadVerificationError:
203 case ErrorCode::kDownloadNewPartitionInfoError:
204 case ErrorCode::kDownloadWriteError:
205 case ErrorCode::kNewRootfsVerificationError:
206 case ErrorCode::kNewKernelVerificationError:
207 case ErrorCode::kSignedDeltaPayloadExpectedError:
208 case ErrorCode::kDownloadPayloadPubKeyVerificationError:
209 case ErrorCode::kPostinstallBootedFromFirmwareB:
210 case ErrorCode::kDownloadStateInitializationError:
211 case ErrorCode::kDownloadInvalidMetadataMagicString:
212 case ErrorCode::kDownloadSignatureMissingInManifest:
213 case ErrorCode::kDownloadManifestParseError:
214 case ErrorCode::kDownloadMetadataSignatureError:
215 case ErrorCode::kDownloadMetadataSignatureVerificationError:
216 case ErrorCode::kDownloadMetadataSignatureMismatch:
217 case ErrorCode::kDownloadOperationHashVerificationError:
218 case ErrorCode::kDownloadOperationExecutionError:
219 case ErrorCode::kDownloadOperationHashMismatch:
220 case ErrorCode::kOmahaRequestEmptyResponseError:
221 case ErrorCode::kOmahaRequestXMLParseError:
222 case ErrorCode::kDownloadInvalidMetadataSize:
223 case ErrorCode::kDownloadInvalidMetadataSignature:
224 case ErrorCode::kOmahaResponseInvalid:
225 case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
226 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
227 case ErrorCode::kNonCriticalUpdateInOOBE:
228 case ErrorCode::kOmahaErrorInHTTPResponse:
229 case ErrorCode::kDownloadOperationHashMissingError:
230 case ErrorCode::kDownloadMetadataSignatureMissingError:
231 case ErrorCode::kOmahaUpdateDeferredForBackoff:
232 case ErrorCode::kPostinstallPowerwashError:
233 case ErrorCode::kUpdateCanceledByChannelChange:
234 case ErrorCode::kPostinstallFirmwareRONotUpdatable:
235 case ErrorCode::kUnsupportedMajorPayloadVersion:
236 case ErrorCode::kUnsupportedMinorPayloadVersion:
237 case ErrorCode::kOmahaRequestXMLHasEntityDecl:
238 case ErrorCode::kFilesystemVerifierError:
239 case ErrorCode::kUserCanceled:
240 case ErrorCode::kOmahaUpdateIgnoredOverCellular:
241 case ErrorCode::kPayloadTimestampError:
242 case ErrorCode::kUpdatedButNotActive:
243 case ErrorCode::kNoUpdate:
244 case ErrorCode::kRollbackNotPossible:
245 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
246 case ErrorCode::kVerityCalculationError:
247 case ErrorCode::kNotEnoughSpace:
248 case ErrorCode::kDeviceCorrupted:
249 case ErrorCode::kPackageExcludedFromUpdate:
250 case ErrorCode::kUpdateProcessing:
251 case ErrorCode::kUpdateAlreadyInstalled:
252 break;
253
254 // Special flags. These can't happen (we mask them out above) but
255 // the compiler doesn't know that. Just break out so we can warn and
256 // return |kInputMalformed|.
257 case ErrorCode::kUmaReportedMax:
258 case ErrorCode::kOmahaRequestHTTPResponseBase:
259 case ErrorCode::kDevModeFlag:
260 case ErrorCode::kResumedFlag:
261 case ErrorCode::kTestImageFlag:
262 case ErrorCode::kTestOmahaUrlFlag:
263 case ErrorCode::kSpecialFlags:
264 LOG(ERROR) << "Unexpected error code " << base_code;
265 break;
266 }
267
268 return metrics::DownloadErrorCode::kInputMalformed;
269 }
270
GetConnectionType(ConnectionType type,ConnectionTethering tethering)271 metrics::ConnectionType GetConnectionType(ConnectionType type,
272 ConnectionTethering tethering) {
273 switch (type) {
274 case ConnectionType::kUnknown:
275 return metrics::ConnectionType::kUnknown;
276
277 case ConnectionType::kDisconnected:
278 return metrics::ConnectionType::kDisconnected;
279
280 case ConnectionType::kEthernet:
281 if (tethering == ConnectionTethering::kConfirmed)
282 return metrics::ConnectionType::kTetheredEthernet;
283 else
284 return metrics::ConnectionType::kEthernet;
285
286 case ConnectionType::kWifi:
287 if (tethering == ConnectionTethering::kConfirmed)
288 return metrics::ConnectionType::kTetheredWifi;
289 else
290 return metrics::ConnectionType::kWifi;
291
292 case ConnectionType::kCellular:
293 return metrics::ConnectionType::kCellular;
294 }
295
296 LOG(ERROR) << "Unexpected network connection type: type="
297 << static_cast<int>(type)
298 << ", tethering=" << static_cast<int>(tethering);
299
300 return metrics::ConnectionType::kUnknown;
301 }
302
GetPersistedValue(std::string_view key,PrefsInterface * prefs)303 int64_t GetPersistedValue(std::string_view key, PrefsInterface* prefs) {
304 CHECK(prefs);
305 if (!prefs->Exists(key))
306 return 0;
307
308 int64_t stored_value;
309 if (!prefs->GetInt64(key, &stored_value))
310 return 0;
311
312 if (stored_value < 0) {
313 LOG(ERROR) << key << ": Invalid value (" << stored_value
314 << ") in persisted state. Defaulting to 0";
315 return 0;
316 }
317
318 return stored_value;
319 }
320
SetNumReboots(int64_t num_reboots,PrefsInterface * prefs)321 void SetNumReboots(int64_t num_reboots, PrefsInterface* prefs) {
322 CHECK(prefs);
323 prefs->SetInt64(kPrefsNumReboots, num_reboots);
324 LOG(INFO) << "Number of Reboots during current update attempt = "
325 << num_reboots;
326 }
327
SetPayloadAttemptNumber(int64_t payload_attempt_number,PrefsInterface * prefs)328 void SetPayloadAttemptNumber(int64_t payload_attempt_number,
329 PrefsInterface* prefs) {
330 CHECK(prefs);
331 prefs->SetInt64(kPrefsPayloadAttemptNumber, payload_attempt_number);
332 LOG(INFO) << "Payload Attempt Number = " << payload_attempt_number;
333 }
334
SetSystemUpdatedMarker(ClockInterface * clock,PrefsInterface * prefs)335 void SetSystemUpdatedMarker(ClockInterface* clock, PrefsInterface* prefs) {
336 CHECK(prefs);
337 CHECK(clock);
338 Time update_finish_time = clock->GetMonotonicTime();
339 prefs->SetInt64(kPrefsSystemUpdatedMarker,
340 update_finish_time.ToInternalValue());
341 LOG(INFO) << "Updated Marker = " << utils::ToString(update_finish_time);
342 }
343
SetUpdateTimestampStart(const Time & update_start_time,PrefsInterface * prefs)344 void SetUpdateTimestampStart(const Time& update_start_time,
345 PrefsInterface* prefs) {
346 CHECK(prefs);
347 prefs->SetInt64(kPrefsUpdateTimestampStart,
348 update_start_time.ToInternalValue());
349 LOG(INFO) << "Update Monotonic Timestamp Start = "
350 << utils::ToString(update_start_time);
351 }
352
SetUpdateBootTimestampStart(const base::Time & update_start_boot_time,PrefsInterface * prefs)353 void SetUpdateBootTimestampStart(const base::Time& update_start_boot_time,
354 PrefsInterface* prefs) {
355 CHECK(prefs);
356 prefs->SetInt64(kPrefsUpdateBootTimestampStart,
357 update_start_boot_time.ToInternalValue());
358 LOG(INFO) << "Update Boot Timestamp Start = "
359 << utils::ToString(update_start_boot_time);
360 }
361
LoadAndReportTimeToReboot(MetricsReporterInterface * metrics_reporter,PrefsInterface * prefs,ClockInterface * clock)362 bool LoadAndReportTimeToReboot(MetricsReporterInterface* metrics_reporter,
363 PrefsInterface* prefs,
364 ClockInterface* clock) {
365 CHECK(prefs);
366 CHECK(clock);
367 int64_t stored_value = GetPersistedValue(kPrefsSystemUpdatedMarker, prefs);
368 if (stored_value == 0)
369 return false;
370
371 Time system_updated_at = Time::FromInternalValue(stored_value);
372 const auto current_time = clock->GetMonotonicTime();
373 TimeDelta time_to_reboot = current_time - system_updated_at;
374 if (time_to_reboot.ToInternalValue() < 0) {
375 LOG(WARNING) << "time_to_reboot is negative - system_updated_at: "
376 << utils::ToString(system_updated_at)
377 << " current time: " << utils::ToString(current_time);
378 return false;
379 }
380 metrics_reporter->ReportTimeToReboot(time_to_reboot.InMinutes());
381 return true;
382 }
383
384 } // namespace metrics_utils
385 } // namespace chromeos_update_engine
386