• 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/prefs_interface.h"
25 #include "update_engine/system_state.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::kDownloadTransferError:
42       return metrics::AttemptResult::kPayloadDownloadError;
43 
44     case ErrorCode::kDownloadInvalidMetadataSize:
45     case ErrorCode::kDownloadInvalidMetadataMagicString:
46     case ErrorCode::kDownloadMetadataSignatureError:
47     case ErrorCode::kDownloadMetadataSignatureVerificationError:
48     case ErrorCode::kPayloadMismatchedType:
49     case ErrorCode::kUnsupportedMajorPayloadVersion:
50     case ErrorCode::kUnsupportedMinorPayloadVersion:
51     case ErrorCode::kDownloadNewPartitionInfoError:
52     case ErrorCode::kDownloadSignatureMissingInManifest:
53     case ErrorCode::kDownloadManifestParseError:
54     case ErrorCode::kDownloadOperationHashMissingError:
55       return metrics::AttemptResult::kMetadataMalformed;
56 
57     case ErrorCode::kDownloadOperationHashMismatch:
58     case ErrorCode::kDownloadOperationHashVerificationError:
59       return metrics::AttemptResult::kOperationMalformed;
60 
61     case ErrorCode::kDownloadOperationExecutionError:
62     case ErrorCode::kInstallDeviceOpenError:
63     case ErrorCode::kKernelDeviceOpenError:
64     case ErrorCode::kDownloadWriteError:
65     case ErrorCode::kFilesystemCopierError:
66     case ErrorCode::kFilesystemVerifierError:
67       return metrics::AttemptResult::kOperationExecutionError;
68 
69     case ErrorCode::kDownloadMetadataSignatureMismatch:
70       return metrics::AttemptResult::kMetadataVerificationFailed;
71 
72     case ErrorCode::kPayloadSizeMismatchError:
73     case ErrorCode::kPayloadHashMismatchError:
74     case ErrorCode::kDownloadPayloadVerificationError:
75     case ErrorCode::kSignedDeltaPayloadExpectedError:
76     case ErrorCode::kDownloadPayloadPubKeyVerificationError:
77     case ErrorCode::kPayloadTimestampError:
78       return metrics::AttemptResult::kPayloadVerificationFailed;
79 
80     case ErrorCode::kNewRootfsVerificationError:
81     case ErrorCode::kNewKernelVerificationError:
82       return metrics::AttemptResult::kVerificationFailed;
83 
84     case ErrorCode::kPostinstallRunnerError:
85     case ErrorCode::kPostinstallBootedFromFirmwareB:
86     case ErrorCode::kPostinstallFirmwareRONotUpdatable:
87       return metrics::AttemptResult::kPostInstallFailed;
88 
89     case ErrorCode::kUserCanceled:
90       return metrics::AttemptResult::kUpdateCanceled;
91 
92     // We should never get these errors in the update-attempt stage so
93     // return internal error if this happens.
94     case ErrorCode::kError:
95     case ErrorCode::kOmahaRequestXMLParseError:
96     case ErrorCode::kOmahaRequestError:
97     case ErrorCode::kOmahaResponseHandlerError:
98     case ErrorCode::kDownloadStateInitializationError:
99     case ErrorCode::kOmahaRequestEmptyResponseError:
100     case ErrorCode::kDownloadInvalidMetadataSignature:
101     case ErrorCode::kOmahaResponseInvalid:
102     case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
103     // TODO(deymo): The next two items belong in their own category; they
104     // should not be counted as internal errors. b/27112092
105     case ErrorCode::kOmahaUpdateDeferredPerPolicy:
106     case ErrorCode::kNonCriticalUpdateInOOBE:
107     case ErrorCode::kOmahaErrorInHTTPResponse:
108     case ErrorCode::kDownloadMetadataSignatureMissingError:
109     case ErrorCode::kOmahaUpdateDeferredForBackoff:
110     case ErrorCode::kPostinstallPowerwashError:
111     case ErrorCode::kUpdateCanceledByChannelChange:
112     case ErrorCode::kOmahaRequestXMLHasEntityDecl:
113       return metrics::AttemptResult::kInternalError;
114 
115     // Special flags. These can't happen (we mask them out above) but
116     // the compiler doesn't know that. Just break out so we can warn and
117     // return |kInternalError|.
118     case ErrorCode::kUmaReportedMax:
119     case ErrorCode::kOmahaRequestHTTPResponseBase:
120     case ErrorCode::kDevModeFlag:
121     case ErrorCode::kResumedFlag:
122     case ErrorCode::kTestImageFlag:
123     case ErrorCode::kTestOmahaUrlFlag:
124     case ErrorCode::kSpecialFlags:
125       break;
126   }
127 
128   LOG(ERROR) << "Unexpected error code " << base_code;
129   return metrics::AttemptResult::kInternalError;
130 }
131 
GetDownloadErrorCode(ErrorCode code)132 metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) {
133   ErrorCode base_code = static_cast<ErrorCode>(
134       static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
135 
136   if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
137     int http_status =
138         static_cast<int>(base_code) -
139         static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase);
140     if (http_status >= 200 && http_status <= 599) {
141       return static_cast<metrics::DownloadErrorCode>(
142           static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) +
143           http_status - 200);
144     } else if (http_status == 0) {
145       // The code is using HTTP Status 0 for "Unable to get http
146       // response code."
147       return metrics::DownloadErrorCode::kDownloadError;
148     }
149     LOG(WARNING) << "Unexpected HTTP status code " << http_status;
150     return metrics::DownloadErrorCode::kHttpStatusOther;
151   }
152 
153   switch (base_code) {
154     // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide
155     // variety of errors (proxy errors, host not reachable, timeouts etc.).
156     //
157     // For now just map that to kDownloading. See http://crbug.com/355745
158     // for how we plan to add more detail in the future.
159     case ErrorCode::kDownloadTransferError:
160       return metrics::DownloadErrorCode::kDownloadError;
161 
162     // All of these error codes are not related to downloading so break
163     // out so we can warn and return InputMalformed.
164     case ErrorCode::kSuccess:
165     case ErrorCode::kError:
166     case ErrorCode::kOmahaRequestError:
167     case ErrorCode::kOmahaResponseHandlerError:
168     case ErrorCode::kFilesystemCopierError:
169     case ErrorCode::kPostinstallRunnerError:
170     case ErrorCode::kPayloadMismatchedType:
171     case ErrorCode::kInstallDeviceOpenError:
172     case ErrorCode::kKernelDeviceOpenError:
173     case ErrorCode::kPayloadHashMismatchError:
174     case ErrorCode::kPayloadSizeMismatchError:
175     case ErrorCode::kDownloadPayloadVerificationError:
176     case ErrorCode::kDownloadNewPartitionInfoError:
177     case ErrorCode::kDownloadWriteError:
178     case ErrorCode::kNewRootfsVerificationError:
179     case ErrorCode::kNewKernelVerificationError:
180     case ErrorCode::kSignedDeltaPayloadExpectedError:
181     case ErrorCode::kDownloadPayloadPubKeyVerificationError:
182     case ErrorCode::kPostinstallBootedFromFirmwareB:
183     case ErrorCode::kDownloadStateInitializationError:
184     case ErrorCode::kDownloadInvalidMetadataMagicString:
185     case ErrorCode::kDownloadSignatureMissingInManifest:
186     case ErrorCode::kDownloadManifestParseError:
187     case ErrorCode::kDownloadMetadataSignatureError:
188     case ErrorCode::kDownloadMetadataSignatureVerificationError:
189     case ErrorCode::kDownloadMetadataSignatureMismatch:
190     case ErrorCode::kDownloadOperationHashVerificationError:
191     case ErrorCode::kDownloadOperationExecutionError:
192     case ErrorCode::kDownloadOperationHashMismatch:
193     case ErrorCode::kOmahaRequestEmptyResponseError:
194     case ErrorCode::kOmahaRequestXMLParseError:
195     case ErrorCode::kDownloadInvalidMetadataSize:
196     case ErrorCode::kDownloadInvalidMetadataSignature:
197     case ErrorCode::kOmahaResponseInvalid:
198     case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
199     case ErrorCode::kOmahaUpdateDeferredPerPolicy:
200     case ErrorCode::kNonCriticalUpdateInOOBE:
201     case ErrorCode::kOmahaErrorInHTTPResponse:
202     case ErrorCode::kDownloadOperationHashMissingError:
203     case ErrorCode::kDownloadMetadataSignatureMissingError:
204     case ErrorCode::kOmahaUpdateDeferredForBackoff:
205     case ErrorCode::kPostinstallPowerwashError:
206     case ErrorCode::kUpdateCanceledByChannelChange:
207     case ErrorCode::kPostinstallFirmwareRONotUpdatable:
208     case ErrorCode::kUnsupportedMajorPayloadVersion:
209     case ErrorCode::kUnsupportedMinorPayloadVersion:
210     case ErrorCode::kOmahaRequestXMLHasEntityDecl:
211     case ErrorCode::kFilesystemVerifierError:
212     case ErrorCode::kUserCanceled:
213     case ErrorCode::kPayloadTimestampError:
214       break;
215 
216     // Special flags. These can't happen (we mask them out above) but
217     // the compiler doesn't know that. Just break out so we can warn and
218     // return |kInputMalformed|.
219     case ErrorCode::kUmaReportedMax:
220     case ErrorCode::kOmahaRequestHTTPResponseBase:
221     case ErrorCode::kDevModeFlag:
222     case ErrorCode::kResumedFlag:
223     case ErrorCode::kTestImageFlag:
224     case ErrorCode::kTestOmahaUrlFlag:
225     case ErrorCode::kSpecialFlags:
226       LOG(ERROR) << "Unexpected error code " << base_code;
227       break;
228   }
229 
230   return metrics::DownloadErrorCode::kInputMalformed;
231 }
232 
GetConnectionType(ConnectionType type,ConnectionTethering tethering)233 metrics::ConnectionType GetConnectionType(ConnectionType type,
234                                           ConnectionTethering tethering) {
235   switch (type) {
236     case ConnectionType::kUnknown:
237       return metrics::ConnectionType::kUnknown;
238 
239     case ConnectionType::kEthernet:
240       if (tethering == ConnectionTethering::kConfirmed)
241         return metrics::ConnectionType::kTetheredEthernet;
242       else
243         return metrics::ConnectionType::kEthernet;
244 
245     case ConnectionType::kWifi:
246       if (tethering == ConnectionTethering::kConfirmed)
247         return metrics::ConnectionType::kTetheredWifi;
248       else
249         return metrics::ConnectionType::kWifi;
250 
251     case ConnectionType::kWimax:
252       return metrics::ConnectionType::kWimax;
253 
254     case ConnectionType::kBluetooth:
255       return metrics::ConnectionType::kBluetooth;
256 
257     case ConnectionType::kCellular:
258       return metrics::ConnectionType::kCellular;
259   }
260 
261   LOG(ERROR) << "Unexpected network connection type: type="
262              << static_cast<int>(type)
263              << ", tethering=" << static_cast<int>(tethering);
264 
265   return metrics::ConnectionType::kUnknown;
266 }
267 
WallclockDurationHelper(SystemState * system_state,const std::string & state_variable_key,TimeDelta * out_duration)268 bool WallclockDurationHelper(SystemState* system_state,
269                              const std::string& state_variable_key,
270                              TimeDelta* out_duration) {
271   bool ret = false;
272 
273   Time now = system_state->clock()->GetWallclockTime();
274   int64_t stored_value;
275   if (system_state->prefs()->GetInt64(state_variable_key, &stored_value)) {
276     Time stored_time = Time::FromInternalValue(stored_value);
277     if (stored_time > now) {
278       LOG(ERROR) << "Stored time-stamp used for " << state_variable_key
279                  << " is in the future.";
280     } else {
281       *out_duration = now - stored_time;
282       ret = true;
283     }
284   }
285 
286   if (!system_state->prefs()->SetInt64(state_variable_key,
287                                        now.ToInternalValue())) {
288     LOG(ERROR) << "Error storing time-stamp in " << state_variable_key;
289   }
290 
291   return ret;
292 }
293 
MonotonicDurationHelper(SystemState * system_state,int64_t * storage,TimeDelta * out_duration)294 bool MonotonicDurationHelper(SystemState* system_state,
295                              int64_t* storage,
296                              TimeDelta* out_duration) {
297   bool ret = false;
298 
299   Time now = system_state->clock()->GetMonotonicTime();
300   if (*storage != 0) {
301     Time stored_time = Time::FromInternalValue(*storage);
302     *out_duration = now - stored_time;
303     ret = true;
304   }
305   *storage = now.ToInternalValue();
306 
307   return ret;
308 }
309 
310 }  // namespace metrics_utils
311 }  // namespace chromeos_update_engine
312