metrics_utils.cc 15 KB

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