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 #include "update_engine/system_state.h"
27
28 using base::Time;
29 using base::TimeDelta;
30
31 namespace chromeos_update_engine {
32 namespace metrics_utils {
33
GetAttemptResult(ErrorCode code)34 metrics::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::kUpdatedButNotActive:
43 return metrics::AttemptResult::kUpdateSucceededNotActive;
44
45 case ErrorCode::kDownloadTransferError:
46 case ErrorCode::kInternalLibCurlError:
47 case ErrorCode::kUnresolvedHostError:
48 case ErrorCode::kUnresolvedHostRecovered:
49 return metrics::AttemptResult::kPayloadDownloadError;
50
51 case ErrorCode::kDownloadInvalidMetadataSize:
52 case ErrorCode::kDownloadInvalidMetadataMagicString:
53 case ErrorCode::kDownloadMetadataSignatureError:
54 case ErrorCode::kDownloadMetadataSignatureVerificationError:
55 case ErrorCode::kPayloadMismatchedType:
56 case ErrorCode::kUnsupportedMajorPayloadVersion:
57 case ErrorCode::kUnsupportedMinorPayloadVersion:
58 case ErrorCode::kDownloadNewPartitionInfoError:
59 case ErrorCode::kDownloadSignatureMissingInManifest:
60 case ErrorCode::kDownloadManifestParseError:
61 case ErrorCode::kDownloadOperationHashMissingError:
62 return metrics::AttemptResult::kMetadataMalformed;
63
64 case ErrorCode::kDownloadOperationHashMismatch:
65 case ErrorCode::kDownloadOperationHashVerificationError:
66 return metrics::AttemptResult::kOperationMalformed;
67
68 case ErrorCode::kDownloadOperationExecutionError:
69 case ErrorCode::kInstallDeviceOpenError:
70 case ErrorCode::kKernelDeviceOpenError:
71 case ErrorCode::kDownloadWriteError:
72 case ErrorCode::kFilesystemCopierError:
73 case ErrorCode::kFilesystemVerifierError:
74 case ErrorCode::kVerityCalculationError:
75 case ErrorCode::kNotEnoughSpace:
76 case ErrorCode::kDeviceCorrupted:
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 return metrics::AttemptResult::kPostInstallFailed;
99
100 case ErrorCode::kUserCanceled:
101 return metrics::AttemptResult::kUpdateCanceled;
102
103 // We should never get these errors in the update-attempt stage so
104 // return internal error if this happens.
105 case ErrorCode::kError:
106 case ErrorCode::kOmahaRequestXMLParseError:
107 case ErrorCode::kOmahaRequestError:
108 case ErrorCode::kOmahaResponseHandlerError:
109 case ErrorCode::kDownloadStateInitializationError:
110 case ErrorCode::kOmahaRequestEmptyResponseError:
111 case ErrorCode::kDownloadInvalidMetadataSignature:
112 case ErrorCode::kOmahaResponseInvalid:
113 case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
114 // TODO(deymo): The next two items belong in their own category; they
115 // should not be counted as internal errors. b/27112092
116 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
117 case ErrorCode::kNonCriticalUpdateInOOBE:
118 case ErrorCode::kOmahaErrorInHTTPResponse:
119 case ErrorCode::kDownloadMetadataSignatureMissingError:
120 case ErrorCode::kOmahaUpdateDeferredForBackoff:
121 case ErrorCode::kPostinstallPowerwashError:
122 case ErrorCode::kUpdateCanceledByChannelChange:
123 case ErrorCode::kOmahaRequestXMLHasEntityDecl:
124 case ErrorCode::kOmahaUpdateIgnoredOverCellular:
125 case ErrorCode::kNoUpdate:
126 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
127 return metrics::AttemptResult::kInternalError;
128
129 // Special flags. These can't happen (we mask them out above) but
130 // the compiler doesn't know that. Just break out so we can warn and
131 // return |kInternalError|.
132 case ErrorCode::kUmaReportedMax:
133 case ErrorCode::kOmahaRequestHTTPResponseBase:
134 case ErrorCode::kDevModeFlag:
135 case ErrorCode::kResumedFlag:
136 case ErrorCode::kTestImageFlag:
137 case ErrorCode::kTestOmahaUrlFlag:
138 case ErrorCode::kSpecialFlags:
139 break;
140 }
141
142 LOG(ERROR) << "Unexpected error code " << base_code;
143 return metrics::AttemptResult::kInternalError;
144 }
145
GetDownloadErrorCode(ErrorCode code)146 metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) {
147 ErrorCode base_code = static_cast<ErrorCode>(
148 static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
149
150 if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
151 int http_status =
152 static_cast<int>(base_code) -
153 static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase);
154 if (http_status >= 200 && http_status <= 599) {
155 return static_cast<metrics::DownloadErrorCode>(
156 static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) +
157 http_status - 200);
158 } else if (http_status == 0) {
159 // The code is using HTTP Status 0 for "Unable to get http
160 // response code."
161 return metrics::DownloadErrorCode::kDownloadError;
162 }
163 LOG(WARNING) << "Unexpected HTTP status code " << http_status;
164 return metrics::DownloadErrorCode::kHttpStatusOther;
165 }
166
167 switch (base_code) {
168 // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide
169 // variety of errors (proxy errors, host not reachable, timeouts etc.).
170 //
171 // For now just map that to kDownloading. See http://crbug.com/355745
172 // for how we plan to add more detail in the future.
173 case ErrorCode::kDownloadTransferError:
174 return metrics::DownloadErrorCode::kDownloadError;
175
176 case ErrorCode::kInternalLibCurlError:
177 return metrics::DownloadErrorCode::kInternalLibCurlError;
178 case ErrorCode::kUnresolvedHostError:
179 return metrics::DownloadErrorCode::kUnresolvedHostError;
180 case ErrorCode::kUnresolvedHostRecovered:
181 return metrics::DownloadErrorCode::kUnresolvedHostRecovered;
182
183 // All of these error codes are not related to downloading so break
184 // out so we can warn and return InputMalformed.
185 case ErrorCode::kSuccess:
186 case ErrorCode::kError:
187 case ErrorCode::kOmahaRequestError:
188 case ErrorCode::kOmahaResponseHandlerError:
189 case ErrorCode::kFilesystemCopierError:
190 case ErrorCode::kPostinstallRunnerError:
191 case ErrorCode::kPayloadMismatchedType:
192 case ErrorCode::kInstallDeviceOpenError:
193 case ErrorCode::kKernelDeviceOpenError:
194 case ErrorCode::kPayloadHashMismatchError:
195 case ErrorCode::kPayloadSizeMismatchError:
196 case ErrorCode::kDownloadPayloadVerificationError:
197 case ErrorCode::kDownloadNewPartitionInfoError:
198 case ErrorCode::kDownloadWriteError:
199 case ErrorCode::kNewRootfsVerificationError:
200 case ErrorCode::kNewKernelVerificationError:
201 case ErrorCode::kSignedDeltaPayloadExpectedError:
202 case ErrorCode::kDownloadPayloadPubKeyVerificationError:
203 case ErrorCode::kPostinstallBootedFromFirmwareB:
204 case ErrorCode::kDownloadStateInitializationError:
205 case ErrorCode::kDownloadInvalidMetadataMagicString:
206 case ErrorCode::kDownloadSignatureMissingInManifest:
207 case ErrorCode::kDownloadManifestParseError:
208 case ErrorCode::kDownloadMetadataSignatureError:
209 case ErrorCode::kDownloadMetadataSignatureVerificationError:
210 case ErrorCode::kDownloadMetadataSignatureMismatch:
211 case ErrorCode::kDownloadOperationHashVerificationError:
212 case ErrorCode::kDownloadOperationExecutionError:
213 case ErrorCode::kDownloadOperationHashMismatch:
214 case ErrorCode::kOmahaRequestEmptyResponseError:
215 case ErrorCode::kOmahaRequestXMLParseError:
216 case ErrorCode::kDownloadInvalidMetadataSize:
217 case ErrorCode::kDownloadInvalidMetadataSignature:
218 case ErrorCode::kOmahaResponseInvalid:
219 case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
220 case ErrorCode::kOmahaUpdateDeferredPerPolicy:
221 case ErrorCode::kNonCriticalUpdateInOOBE:
222 case ErrorCode::kOmahaErrorInHTTPResponse:
223 case ErrorCode::kDownloadOperationHashMissingError:
224 case ErrorCode::kDownloadMetadataSignatureMissingError:
225 case ErrorCode::kOmahaUpdateDeferredForBackoff:
226 case ErrorCode::kPostinstallPowerwashError:
227 case ErrorCode::kUpdateCanceledByChannelChange:
228 case ErrorCode::kPostinstallFirmwareRONotUpdatable:
229 case ErrorCode::kUnsupportedMajorPayloadVersion:
230 case ErrorCode::kUnsupportedMinorPayloadVersion:
231 case ErrorCode::kOmahaRequestXMLHasEntityDecl:
232 case ErrorCode::kFilesystemVerifierError:
233 case ErrorCode::kUserCanceled:
234 case ErrorCode::kOmahaUpdateIgnoredOverCellular:
235 case ErrorCode::kPayloadTimestampError:
236 case ErrorCode::kUpdatedButNotActive:
237 case ErrorCode::kNoUpdate:
238 case ErrorCode::kRollbackNotPossible:
239 case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
240 case ErrorCode::kVerityCalculationError:
241 case ErrorCode::kNotEnoughSpace:
242 case ErrorCode::kDeviceCorrupted:
243 break;
244
245 // Special flags. These can't happen (we mask them out above) but
246 // the compiler doesn't know that. Just break out so we can warn and
247 // return |kInputMalformed|.
248 case ErrorCode::kUmaReportedMax:
249 case ErrorCode::kOmahaRequestHTTPResponseBase:
250 case ErrorCode::kDevModeFlag:
251 case ErrorCode::kResumedFlag:
252 case ErrorCode::kTestImageFlag:
253 case ErrorCode::kTestOmahaUrlFlag:
254 case ErrorCode::kSpecialFlags:
255 LOG(ERROR) << "Unexpected error code " << base_code;
256 break;
257 }
258
259 return metrics::DownloadErrorCode::kInputMalformed;
260 }
261
GetConnectionType(ConnectionType type,ConnectionTethering tethering)262 metrics::ConnectionType GetConnectionType(ConnectionType type,
263 ConnectionTethering tethering) {
264 switch (type) {
265 case ConnectionType::kUnknown:
266 return metrics::ConnectionType::kUnknown;
267
268 case ConnectionType::kDisconnected:
269 return metrics::ConnectionType::kDisconnected;
270
271 case ConnectionType::kEthernet:
272 if (tethering == ConnectionTethering::kConfirmed)
273 return metrics::ConnectionType::kTetheredEthernet;
274 else
275 return metrics::ConnectionType::kEthernet;
276
277 case ConnectionType::kWifi:
278 if (tethering == ConnectionTethering::kConfirmed)
279 return metrics::ConnectionType::kTetheredWifi;
280 else
281 return metrics::ConnectionType::kWifi;
282
283 case ConnectionType::kWimax:
284 return metrics::ConnectionType::kWimax;
285
286 case ConnectionType::kBluetooth:
287 return metrics::ConnectionType::kBluetooth;
288
289 case ConnectionType::kCellular:
290 return metrics::ConnectionType::kCellular;
291 }
292
293 LOG(ERROR) << "Unexpected network connection type: type="
294 << static_cast<int>(type)
295 << ", tethering=" << static_cast<int>(tethering);
296
297 return metrics::ConnectionType::kUnknown;
298 }
299
WallclockDurationHelper(SystemState * system_state,const std::string & state_variable_key,TimeDelta * out_duration)300 bool WallclockDurationHelper(SystemState* system_state,
301 const std::string& state_variable_key,
302 TimeDelta* out_duration) {
303 bool ret = false;
304
305 Time now = system_state->clock()->GetWallclockTime();
306 int64_t stored_value;
307 if (system_state->prefs()->GetInt64(state_variable_key, &stored_value)) {
308 Time stored_time = Time::FromInternalValue(stored_value);
309 if (stored_time > now) {
310 LOG(ERROR) << "Stored time-stamp used for " << state_variable_key
311 << " is in the future.";
312 } else {
313 *out_duration = now - stored_time;
314 ret = true;
315 }
316 }
317
318 if (!system_state->prefs()->SetInt64(state_variable_key,
319 now.ToInternalValue())) {
320 LOG(ERROR) << "Error storing time-stamp in " << state_variable_key;
321 }
322
323 return ret;
324 }
325
MonotonicDurationHelper(SystemState * system_state,int64_t * storage,TimeDelta * out_duration)326 bool MonotonicDurationHelper(SystemState* system_state,
327 int64_t* storage,
328 TimeDelta* out_duration) {
329 bool ret = false;
330
331 Time now = system_state->clock()->GetMonotonicTime();
332 if (*storage != 0) {
333 Time stored_time = Time::FromInternalValue(*storage);
334 *out_duration = now - stored_time;
335 ret = true;
336 }
337 *storage = now.ToInternalValue();
338
339 return ret;
340 }
341
GetPersistedValue(const std::string & key,PrefsInterface * prefs)342 int64_t GetPersistedValue(const std::string& key, PrefsInterface* prefs) {
343 CHECK(prefs);
344 if (!prefs->Exists(key))
345 return 0;
346
347 int64_t stored_value;
348 if (!prefs->GetInt64(key, &stored_value))
349 return 0;
350
351 if (stored_value < 0) {
352 LOG(ERROR) << key << ": Invalid value (" << stored_value
353 << ") in persisted state. Defaulting to 0";
354 return 0;
355 }
356
357 return stored_value;
358 }
359
SetNumReboots(int64_t num_reboots,PrefsInterface * prefs)360 void SetNumReboots(int64_t num_reboots, PrefsInterface* prefs) {
361 CHECK(prefs);
362 prefs->SetInt64(kPrefsNumReboots, num_reboots);
363 LOG(INFO) << "Number of Reboots during current update attempt = "
364 << num_reboots;
365 }
366
SetPayloadAttemptNumber(int64_t payload_attempt_number,PrefsInterface * prefs)367 void SetPayloadAttemptNumber(int64_t payload_attempt_number,
368 PrefsInterface* prefs) {
369 CHECK(prefs);
370 prefs->SetInt64(kPrefsPayloadAttemptNumber, payload_attempt_number);
371 LOG(INFO) << "Payload Attempt Number = " << payload_attempt_number;
372 }
373
SetSystemUpdatedMarker(ClockInterface * clock,PrefsInterface * prefs)374 void SetSystemUpdatedMarker(ClockInterface* clock, PrefsInterface* prefs) {
375 CHECK(prefs);
376 CHECK(clock);
377 Time update_finish_time = clock->GetMonotonicTime();
378 prefs->SetInt64(kPrefsSystemUpdatedMarker,
379 update_finish_time.ToInternalValue());
380 LOG(INFO) << "Updated Marker = " << utils::ToString(update_finish_time);
381 }
382
SetUpdateTimestampStart(const Time & update_start_time,PrefsInterface * prefs)383 void SetUpdateTimestampStart(const Time& update_start_time,
384 PrefsInterface* prefs) {
385 CHECK(prefs);
386 prefs->SetInt64(kPrefsUpdateTimestampStart,
387 update_start_time.ToInternalValue());
388 LOG(INFO) << "Update Monotonic Timestamp Start = "
389 << utils::ToString(update_start_time);
390 }
391
SetUpdateBootTimestampStart(const base::Time & update_start_boot_time,PrefsInterface * prefs)392 void SetUpdateBootTimestampStart(const base::Time& update_start_boot_time,
393 PrefsInterface* prefs) {
394 CHECK(prefs);
395 prefs->SetInt64(kPrefsUpdateBootTimestampStart,
396 update_start_boot_time.ToInternalValue());
397 LOG(INFO) << "Update Boot Timestamp Start = "
398 << utils::ToString(update_start_boot_time);
399 }
400
LoadAndReportTimeToReboot(MetricsReporterInterface * metrics_reporter,PrefsInterface * prefs,ClockInterface * clock)401 bool LoadAndReportTimeToReboot(MetricsReporterInterface* metrics_reporter,
402 PrefsInterface* prefs,
403 ClockInterface* clock) {
404 CHECK(prefs);
405 CHECK(clock);
406 int64_t stored_value = GetPersistedValue(kPrefsSystemUpdatedMarker, prefs);
407 if (stored_value == 0)
408 return false;
409
410 Time system_updated_at = Time::FromInternalValue(stored_value);
411 base::TimeDelta time_to_reboot =
412 clock->GetMonotonicTime() - system_updated_at;
413 if (time_to_reboot.ToInternalValue() < 0) {
414 LOG(ERROR) << "time_to_reboot is negative - system_updated_at: "
415 << utils::ToString(system_updated_at);
416 return false;
417 }
418 metrics_reporter->ReportTimeToReboot(time_to_reboot.InMinutes());
419 return true;
420 }
421
422 } // namespace metrics_utils
423 } // namespace chromeos_update_engine
424