• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       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     case ErrorCode::kVerityCalculationError:
72       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:
82     case ErrorCode::kPayloadTimestampError:
83       return metrics::AttemptResult::kPayloadVerificationFailed;
84 
85     case ErrorCode::kNewRootfsVerificationError:
86     case ErrorCode::kNewKernelVerificationError:
87     case ErrorCode::kRollbackNotPossible:
88       return metrics::AttemptResult::kVerificationFailed;
89 
90     case ErrorCode::kPostinstallRunnerError:
91     case ErrorCode::kPostinstallBootedFromFirmwareB:
92     case ErrorCode::kPostinstallFirmwareRONotUpdatable:
93       return metrics::AttemptResult::kPostInstallFailed;
94 
95     case ErrorCode::kUserCanceled:
96       return metrics::AttemptResult::kUpdateCanceled;
97 
98     // 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:
109     // TODO(deymo): The next two items belong in their own category; they
110     // should not be counted as internal errors. b/27112092
111     case ErrorCode::kOmahaUpdateDeferredPerPolicy:
112     case ErrorCode::kNonCriticalUpdateInOOBE:
113     case ErrorCode::kOmahaErrorInHTTPResponse:
114     case ErrorCode::kDownloadMetadataSignatureMissingError:
115     case ErrorCode::kOmahaUpdateDeferredForBackoff:
116     case ErrorCode::kPostinstallPowerwashError:
117     case ErrorCode::kUpdateCanceledByChannelChange:
118     case ErrorCode::kOmahaRequestXMLHasEntityDecl:
119     case ErrorCode::kOmahaUpdateIgnoredOverCellular:
120     case ErrorCode::kNoUpdate:
121     case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
122       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 
GetDownloadErrorCode(ErrorCode code)141 metrics::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:
209     case ErrorCode::kNonCriticalUpdateInOOBE:
210     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:
221     case ErrorCode::kUserCanceled:
222     case ErrorCode::kOmahaUpdateIgnoredOverCellular:
223     case ErrorCode::kPayloadTimestampError:
224     case ErrorCode::kUpdatedButNotActive:
225     case ErrorCode::kNoUpdate:
226     case ErrorCode::kRollbackNotPossible:
227     case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
228     case ErrorCode::kVerityCalculationError:
229       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 
GetConnectionType(ConnectionType type,ConnectionTethering tethering)248 metrics::ConnectionType GetConnectionType(ConnectionType type,
249                                           ConnectionTethering tethering) {
250   switch (type) {
251     case ConnectionType::kUnknown:
252       return metrics::ConnectionType::kUnknown;
253 
254     case ConnectionType::kDisconnected:
255       return metrics::ConnectionType::kDisconnected;
256 
257     case ConnectionType::kEthernet:
258       if (tethering == ConnectionTethering::kConfirmed)
259         return metrics::ConnectionType::kTetheredEthernet;
260       else
261         return metrics::ConnectionType::kEthernet;
262 
263     case ConnectionType::kWifi:
264       if (tethering == ConnectionTethering::kConfirmed)
265         return metrics::ConnectionType::kTetheredWifi;
266       else
267         return metrics::ConnectionType::kWifi;
268 
269     case ConnectionType::kWimax:
270       return metrics::ConnectionType::kWimax;
271 
272     case ConnectionType::kBluetooth:
273       return metrics::ConnectionType::kBluetooth;
274 
275     case ConnectionType::kCellular:
276       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 
WallclockDurationHelper(SystemState * system_state,const std::string & state_variable_key,TimeDelta * out_duration)286 bool 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 
MonotonicDurationHelper(SystemState * system_state,int64_t * storage,TimeDelta * out_duration)312 bool 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 
GetPersistedValue(const std::string & key,PrefsInterface * prefs)328 int64_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 
SetNumReboots(int64_t num_reboots,PrefsInterface * prefs)346 void 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 
SetPayloadAttemptNumber(int64_t payload_attempt_number,PrefsInterface * prefs)353 void 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 
SetSystemUpdatedMarker(ClockInterface * clock,PrefsInterface * prefs)360 void 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 
SetUpdateTimestampStart(const Time & update_start_time,PrefsInterface * prefs)369 void SetUpdateTimestampStart(const Time& update_start_time,
370                              PrefsInterface* prefs) {
371   CHECK(prefs);
372   prefs->SetInt64(kPrefsUpdateTimestampStart,
373                   update_start_time.ToInternalValue());
374   LOG(INFO) << "Update Monotonic Timestamp Start = "
375             << utils::ToString(update_start_time);
376 }
377 
SetUpdateBootTimestampStart(const base::Time & update_start_boot_time,PrefsInterface * prefs)378 void 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 
LoadAndReportTimeToReboot(MetricsReporterInterface * metrics_reporter,PrefsInterface * prefs,ClockInterface * clock)387 bool 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 
408 }  // namespace metrics_utils
409 }  // namespace chromeos_update_engine
410