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