| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. | 
 | 2 | // Use of this source code is governed by a BSD-style license that can be | 
 | 3 | // found in the LICENSE file. | 
 | 4 |  | 
 | 5 | #include "update_engine/payload_state.h" | 
 | 6 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 7 | #include <algorithm> | 
 | 8 |  | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 9 | #include <base/logging.h> | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 10 | #include "base/string_util.h" | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 11 | #include <base/stringprintf.h> | 
 | 12 |  | 
| David Zeuthen | f413fe5 | 2013-04-22 14:04:39 -0700 | [diff] [blame] | 13 | #include "update_engine/clock.h" | 
| Jay Srinivasan | d29695d | 2013-04-08 15:08:05 -0700 | [diff] [blame] | 14 | #include "update_engine/constants.h" | 
| Alex Deymo | 4243291 | 2013-07-12 20:21:15 -0700 | [diff] [blame] | 15 | #include "update_engine/hardware_interface.h" | 
 | 16 | #include "update_engine/install_plan.h" | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 17 | #include "update_engine/prefs.h" | 
 | 18 | #include "update_engine/system_state.h" | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 19 | #include "update_engine/utils.h" | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 20 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 21 | using base::Time; | 
 | 22 | using base::TimeDelta; | 
 | 23 | using std::min; | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 24 | using std::string; | 
 | 25 |  | 
 | 26 | namespace chromeos_update_engine { | 
 | 27 |  | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 28 | const TimeDelta PayloadState::kDurationSlack = TimeDelta::FromSeconds(600); | 
 | 29 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 30 | // We want to upperbound backoffs to 16 days | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 31 | static const int kMaxBackoffDays = 16; | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 32 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 33 | // We want to randomize retry attempts after the backoff by +/- 6 hours. | 
 | 34 | static const uint32_t kMaxBackoffFuzzMinutes = 12 * 60; | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 35 |  | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 36 | PayloadState::PayloadState() | 
 | 37 |     : prefs_(NULL), | 
 | 38 |       payload_attempt_number_(0), | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 39 |       full_payload_attempt_number_(0), | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 40 |       url_index_(0), | 
| David Zeuthen | cc6f996 | 2013-04-18 11:57:24 -0700 | [diff] [blame] | 41 |       url_failure_count_(0), | 
 | 42 |       url_switch_count_(0) { | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 43 |  for (int i = 0; i <= kNumDownloadSources; i++) | 
 | 44 |   total_bytes_downloaded_[i] = current_bytes_downloaded_[i] = 0; | 
 | 45 | } | 
 | 46 |  | 
 | 47 | bool PayloadState::Initialize(SystemState* system_state) { | 
 | 48 |   system_state_ = system_state; | 
 | 49 |   prefs_ = system_state_->prefs(); | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 50 |   powerwash_safe_prefs_ = system_state_->powerwash_safe_prefs(); | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 51 |   LoadResponseSignature(); | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 52 |   LoadPayloadAttemptNumber(); | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 53 |   LoadFullPayloadAttemptNumber(); | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 54 |   LoadUrlIndex(); | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 55 |   LoadUrlFailureCount(); | 
| David Zeuthen | cc6f996 | 2013-04-18 11:57:24 -0700 | [diff] [blame] | 56 |   LoadUrlSwitchCount(); | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 57 |   LoadBackoffExpiryTime(); | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 58 |   LoadUpdateTimestampStart(); | 
 | 59 |   // The LoadUpdateDurationUptime() method relies on LoadUpdateTimestampStart() | 
 | 60 |   // being called before it. Don't reorder. | 
 | 61 |   LoadUpdateDurationUptime(); | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 62 |   for (int i = 0; i < kNumDownloadSources; i++) { | 
 | 63 |     DownloadSource source = static_cast<DownloadSource>(i); | 
 | 64 |     LoadCurrentBytesDownloaded(source); | 
 | 65 |     LoadTotalBytesDownloaded(source); | 
 | 66 |   } | 
| Chris Sosa | be45bef | 2013-04-09 18:25:12 -0700 | [diff] [blame] | 67 |   LoadNumReboots(); | 
| David Zeuthen | a573d6f | 2013-06-14 16:13:36 -0700 | [diff] [blame] | 68 |   LoadNumResponsesSeen(); | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 69 |   LoadRollbackVersion(); | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 70 |   return true; | 
 | 71 | } | 
 | 72 |  | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 73 | void PayloadState::SetResponse(const OmahaResponse& omaha_response) { | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 74 |   // Always store the latest response. | 
 | 75 |   response_ = omaha_response; | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 76 |  | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 77 |   // Compute the candidate URLs first as they are used to calculate the | 
 | 78 |   // response signature so that a change in enterprise policy for | 
 | 79 |   // HTTP downloads being enabled or not could be honored as soon as the | 
 | 80 |   // next update check happens. | 
 | 81 |   ComputeCandidateUrls(); | 
 | 82 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 83 |   // Check if the "signature" of this response (i.e. the fields we care about) | 
 | 84 |   // has changed. | 
 | 85 |   string new_response_signature = CalculateResponseSignature(); | 
 | 86 |   bool has_response_changed = (response_signature_ != new_response_signature); | 
 | 87 |  | 
 | 88 |   // If the response has changed, we should persist the new signature and | 
 | 89 |   // clear away all the existing state. | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 90 |   if (has_response_changed) { | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 91 |     LOG(INFO) << "Resetting all persisted state as this is a new response"; | 
| David Zeuthen | a573d6f | 2013-06-14 16:13:36 -0700 | [diff] [blame] | 92 |     SetNumResponsesSeen(num_responses_seen_ + 1); | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 93 |     SetResponseSignature(new_response_signature); | 
 | 94 |     ResetPersistedState(); | 
| Alex Deymo | b33b0f0 | 2013-08-08 21:10:02 -0700 | [diff] [blame] | 95 |     ReportUpdatesAbandonedEventCountMetric(); | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 96 |     return; | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 97 |   } | 
 | 98 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 99 |   // This is the earliest point at which we can validate whether the URL index | 
 | 100 |   // we loaded from the persisted state is a valid value. If the response | 
 | 101 |   // hasn't changed but the URL index is invalid, it's indicative of some | 
 | 102 |   // tampering of the persisted state. | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 103 |   if (static_cast<uint32_t>(url_index_) >= candidate_urls_.size()) { | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 104 |     LOG(INFO) << "Resetting all payload state as the url index seems to have " | 
 | 105 |                  "been tampered with"; | 
 | 106 |     ResetPersistedState(); | 
 | 107 |     return; | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 108 |   } | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 109 |  | 
 | 110 |   // Update the current download source which depends on the latest value of | 
 | 111 |   // the response. | 
 | 112 |   UpdateCurrentDownloadSource(); | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 113 | } | 
 | 114 |  | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 115 | void PayloadState::DownloadComplete() { | 
 | 116 |   LOG(INFO) << "Payload downloaded successfully"; | 
 | 117 |   IncrementPayloadAttemptNumber(); | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 118 |   IncrementFullPayloadAttemptNumber(); | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 119 | } | 
 | 120 |  | 
 | 121 | void PayloadState::DownloadProgress(size_t count) { | 
 | 122 |   if (count == 0) | 
 | 123 |     return; | 
 | 124 |  | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 125 |   CalculateUpdateDurationUptime(); | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 126 |   UpdateBytesDownloaded(count); | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 127 |  | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 128 |   // We've received non-zero bytes from a recent download operation.  Since our | 
 | 129 |   // URL failure count is meant to penalize a URL only for consecutive | 
 | 130 |   // failures, downloading bytes successfully means we should reset the failure | 
 | 131 |   // count (as we know at least that the URL is working). In future, we can | 
 | 132 |   // design this to be more sophisticated to check for more intelligent failure | 
 | 133 |   // patterns, but right now, even 1 byte downloaded will mark the URL to be | 
 | 134 |   // good unless it hits 10 (or configured number of) consecutive failures | 
 | 135 |   // again. | 
 | 136 |  | 
 | 137 |   if (GetUrlFailureCount() == 0) | 
 | 138 |     return; | 
 | 139 |  | 
 | 140 |   LOG(INFO) << "Resetting failure count of Url" << GetUrlIndex() | 
 | 141 |             << " to 0 as we received " << count << " bytes successfully"; | 
 | 142 |   SetUrlFailureCount(0); | 
 | 143 | } | 
 | 144 |  | 
| Chris Sosa | be45bef | 2013-04-09 18:25:12 -0700 | [diff] [blame] | 145 | void PayloadState::UpdateResumed() { | 
 | 146 |   LOG(INFO) << "Resuming an update that was previously started."; | 
 | 147 |   UpdateNumReboots(); | 
 | 148 | } | 
 | 149 |  | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 150 | void PayloadState::UpdateRestarted() { | 
 | 151 |   LOG(INFO) << "Starting a new update"; | 
 | 152 |   ResetDownloadSourcesOnNewUpdate(); | 
| Chris Sosa | be45bef | 2013-04-09 18:25:12 -0700 | [diff] [blame] | 153 |   SetNumReboots(0); | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 154 | } | 
 | 155 |  | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 156 | void PayloadState::UpdateSucceeded() { | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 157 |   // Send the relevant metrics that are tracked in this class to UMA. | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 158 |   CalculateUpdateDurationUptime(); | 
| David Zeuthen | f413fe5 | 2013-04-22 14:04:39 -0700 | [diff] [blame] | 159 |   SetUpdateTimestampEnd(system_state_->clock()->GetWallclockTime()); | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 160 |   ReportBytesDownloadedMetrics(); | 
| David Zeuthen | cc6f996 | 2013-04-18 11:57:24 -0700 | [diff] [blame] | 161 |   ReportUpdateUrlSwitchesMetric(); | 
| Chris Sosa | be45bef | 2013-04-09 18:25:12 -0700 | [diff] [blame] | 162 |   ReportRebootMetrics(); | 
| David Zeuthen | 674c318 | 2013-04-18 14:05:20 -0700 | [diff] [blame] | 163 |   ReportDurationMetrics(); | 
| David Zeuthen | a573d6f | 2013-06-14 16:13:36 -0700 | [diff] [blame] | 164 |   ReportUpdatesAbandonedCountMetric(); | 
| Alex Deymo | 1c656c4 | 2013-06-28 11:02:14 -0700 | [diff] [blame] | 165 |   ReportPayloadTypeMetric(); | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 166 |   ReportAttemptsCountMetrics(); | 
| David Zeuthen | a573d6f | 2013-06-14 16:13:36 -0700 | [diff] [blame] | 167 |  | 
 | 168 |   // Reset the number of responses seen since it counts from the last | 
 | 169 |   // successful update, e.g. now. | 
 | 170 |   SetNumResponsesSeen(0); | 
| David Zeuthen | e4c58bf | 2013-06-18 17:26:50 -0700 | [diff] [blame] | 171 |  | 
 | 172 |   CreateSystemUpdatedMarkerFile(); | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 173 | } | 
 | 174 |  | 
| David Zeuthen | a99981f | 2013-04-29 13:42:47 -0700 | [diff] [blame] | 175 | void PayloadState::UpdateFailed(ErrorCode error) { | 
 | 176 |   ErrorCode base_error = utils::GetBaseErrorCode(error); | 
| Jay Srinivasan | 55f50c2 | 2013-01-10 19:24:35 -0800 | [diff] [blame] | 177 |   LOG(INFO) << "Updating payload state for error code: " << base_error | 
 | 178 |             << " (" << utils::CodeToString(base_error) << ")"; | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 179 |  | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 180 |   if (candidate_urls_.size() == 0) { | 
 | 181 |     // This means we got this error even before we got a valid Omaha response | 
 | 182 |     // or don't have any valid candidates in the Omaha response. | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 183 |     // So we should not advance the url_index_ in such cases. | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 184 |     LOG(INFO) << "Ignoring failures until we get a valid Omaha response."; | 
 | 185 |     return; | 
 | 186 |   } | 
 | 187 |  | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 188 |   switch (base_error) { | 
 | 189 |     // Errors which are good indicators of a problem with a particular URL or | 
 | 190 |     // the protocol used in the URL or entities in the communication channel | 
 | 191 |     // (e.g. proxies). We should try the next available URL in the next update | 
 | 192 |     // check to quickly recover from these errors. | 
| David Zeuthen | a99981f | 2013-04-29 13:42:47 -0700 | [diff] [blame] | 193 |     case kErrorCodePayloadHashMismatchError: | 
 | 194 |     case kErrorCodePayloadSizeMismatchError: | 
 | 195 |     case kErrorCodeDownloadPayloadVerificationError: | 
 | 196 |     case kErrorCodeDownloadPayloadPubKeyVerificationError: | 
 | 197 |     case kErrorCodeSignedDeltaPayloadExpectedError: | 
 | 198 |     case kErrorCodeDownloadInvalidMetadataMagicString: | 
 | 199 |     case kErrorCodeDownloadSignatureMissingInManifest: | 
 | 200 |     case kErrorCodeDownloadManifestParseError: | 
 | 201 |     case kErrorCodeDownloadMetadataSignatureError: | 
 | 202 |     case kErrorCodeDownloadMetadataSignatureVerificationError: | 
 | 203 |     case kErrorCodeDownloadMetadataSignatureMismatch: | 
 | 204 |     case kErrorCodeDownloadOperationHashVerificationError: | 
 | 205 |     case kErrorCodeDownloadOperationExecutionError: | 
 | 206 |     case kErrorCodeDownloadOperationHashMismatch: | 
 | 207 |     case kErrorCodeDownloadInvalidMetadataSize: | 
 | 208 |     case kErrorCodeDownloadInvalidMetadataSignature: | 
 | 209 |     case kErrorCodeDownloadOperationHashMissingError: | 
 | 210 |     case kErrorCodeDownloadMetadataSignatureMissingError: | 
| Gilad Arnold | 21504f0 | 2013-05-24 08:51:22 -0700 | [diff] [blame] | 211 |     case kErrorCodePayloadMismatchedType: | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 212 |       IncrementUrlIndex(); | 
 | 213 |       break; | 
 | 214 |  | 
 | 215 |     // Errors which seem to be just transient network/communication related | 
 | 216 |     // failures and do not indicate any inherent problem with the URL itself. | 
 | 217 |     // So, we should keep the current URL but just increment the | 
 | 218 |     // failure count to give it more chances. This way, while we maximize our | 
 | 219 |     // chances of downloading from the URLs that appear earlier in the response | 
 | 220 |     // (because download from a local server URL that appears earlier in a | 
 | 221 |     // response is preferable than downloading from the next URL which could be | 
 | 222 |     // a internet URL and thus could be more expensive). | 
| David Zeuthen | a99981f | 2013-04-29 13:42:47 -0700 | [diff] [blame] | 223 |     case kErrorCodeError: | 
 | 224 |     case kErrorCodeDownloadTransferError: | 
 | 225 |     case kErrorCodeDownloadWriteError: | 
 | 226 |     case kErrorCodeDownloadStateInitializationError: | 
 | 227 |     case kErrorCodeOmahaErrorInHTTPResponse: // Aggregate code for HTTP errors. | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 228 |       IncrementFailureCount(); | 
 | 229 |       break; | 
 | 230 |  | 
 | 231 |     // Errors which are not specific to a URL and hence shouldn't result in | 
 | 232 |     // the URL being penalized. This can happen in two cases: | 
 | 233 |     // 1. We haven't started downloading anything: These errors don't cost us | 
 | 234 |     // anything in terms of actual payload bytes, so we should just do the | 
 | 235 |     // regular retries at the next update check. | 
 | 236 |     // 2. We have successfully downloaded the payload: In this case, the | 
 | 237 |     // payload attempt number would have been incremented and would take care | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 238 |     // of the backoff at the next update check. | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 239 |     // In either case, there's no need to update URL index or failure count. | 
| David Zeuthen | a99981f | 2013-04-29 13:42:47 -0700 | [diff] [blame] | 240 |     case kErrorCodeOmahaRequestError: | 
 | 241 |     case kErrorCodeOmahaResponseHandlerError: | 
 | 242 |     case kErrorCodePostinstallRunnerError: | 
 | 243 |     case kErrorCodeFilesystemCopierError: | 
 | 244 |     case kErrorCodeInstallDeviceOpenError: | 
 | 245 |     case kErrorCodeKernelDeviceOpenError: | 
 | 246 |     case kErrorCodeDownloadNewPartitionInfoError: | 
 | 247 |     case kErrorCodeNewRootfsVerificationError: | 
 | 248 |     case kErrorCodeNewKernelVerificationError: | 
 | 249 |     case kErrorCodePostinstallBootedFromFirmwareB: | 
| Don Garrett | 81018e0 | 2013-07-30 18:46:31 -0700 | [diff] [blame] | 250 |     case kErrorCodePostinstallFirmwareRONotUpdatable: | 
| David Zeuthen | a99981f | 2013-04-29 13:42:47 -0700 | [diff] [blame] | 251 |     case kErrorCodeOmahaRequestEmptyResponseError: | 
 | 252 |     case kErrorCodeOmahaRequestXMLParseError: | 
 | 253 |     case kErrorCodeOmahaResponseInvalid: | 
 | 254 |     case kErrorCodeOmahaUpdateIgnoredPerPolicy: | 
 | 255 |     case kErrorCodeOmahaUpdateDeferredPerPolicy: | 
 | 256 |     case kErrorCodeOmahaUpdateDeferredForBackoff: | 
 | 257 |     case kErrorCodePostinstallPowerwashError: | 
 | 258 |     case kErrorCodeUpdateCanceledByChannelChange: | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 259 |       LOG(INFO) << "Not incrementing URL index or failure count for this error"; | 
 | 260 |       break; | 
 | 261 |  | 
| David Zeuthen | a99981f | 2013-04-29 13:42:47 -0700 | [diff] [blame] | 262 |     case kErrorCodeSuccess:                            // success code | 
| David Zeuthen | a99981f | 2013-04-29 13:42:47 -0700 | [diff] [blame] | 263 |     case kErrorCodeUmaReportedMax:                     // not an error code | 
 | 264 |     case kErrorCodeOmahaRequestHTTPResponseBase:       // aggregated already | 
 | 265 |     case kErrorCodeDevModeFlag:                       // not an error code | 
 | 266 |     case kErrorCodeResumedFlag:                        // not an error code | 
 | 267 |     case kErrorCodeTestImageFlag:                      // not an error code | 
 | 268 |     case kErrorCodeTestOmahaUrlFlag:                   // not an error code | 
 | 269 |     case kErrorCodeSpecialFlags:                       // not an error code | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 270 |       // These shouldn't happen. Enumerating these  explicitly here so that we | 
 | 271 |       // can let the compiler warn about new error codes that are added to | 
 | 272 |       // action_processor.h but not added here. | 
 | 273 |       LOG(WARNING) << "Unexpected error code for UpdateFailed"; | 
 | 274 |       break; | 
 | 275 |  | 
 | 276 |     // Note: Not adding a default here so as to let the compiler warn us of | 
 | 277 |     // any new enums that were added in the .h but not listed in this switch. | 
 | 278 |   } | 
 | 279 | } | 
 | 280 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 281 | bool PayloadState::ShouldBackoffDownload() { | 
 | 282 |   if (response_.disable_payload_backoff) { | 
 | 283 |     LOG(INFO) << "Payload backoff logic is disabled. " | 
 | 284 |                  "Can proceed with the download"; | 
 | 285 |     return false; | 
 | 286 |   } | 
 | 287 |  | 
 | 288 |   if (response_.is_delta_payload) { | 
 | 289 |     // If delta payloads fail, we want to fallback quickly to full payloads as | 
 | 290 |     // they are more likely to succeed. Exponential backoffs would greatly | 
 | 291 |     // slow down the fallback to full payloads.  So we don't backoff for delta | 
 | 292 |     // payloads. | 
 | 293 |     LOG(INFO) << "No backoffs for delta payloads. " | 
 | 294 |               << "Can proceed with the download"; | 
 | 295 |     return false; | 
 | 296 |   } | 
 | 297 |  | 
 | 298 |   if (!utils::IsOfficialBuild()) { | 
 | 299 |     // Backoffs are needed only for official builds. We do not want any delays | 
 | 300 |     // or update failures due to backoffs during testing or development. | 
 | 301 |     LOG(INFO) << "No backoffs for test/dev images. " | 
 | 302 |               << "Can proceed with the download"; | 
 | 303 |     return false; | 
 | 304 |   } | 
 | 305 |  | 
 | 306 |   if (backoff_expiry_time_.is_null()) { | 
 | 307 |     LOG(INFO) << "No backoff expiry time has been set. " | 
 | 308 |               << "Can proceed with the download"; | 
 | 309 |     return false; | 
 | 310 |   } | 
 | 311 |  | 
 | 312 |   if (backoff_expiry_time_ < Time::Now()) { | 
 | 313 |     LOG(INFO) << "The backoff expiry time (" | 
 | 314 |               << utils::ToString(backoff_expiry_time_) | 
 | 315 |               << ") has elapsed. Can proceed with the download"; | 
 | 316 |     return false; | 
 | 317 |   } | 
 | 318 |  | 
 | 319 |   LOG(INFO) << "Cannot proceed with downloads as we need to backoff until " | 
 | 320 |             << utils::ToString(backoff_expiry_time_); | 
 | 321 |   return true; | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 322 | } | 
 | 323 |  | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 324 | void PayloadState::Rollback() { | 
 | 325 |   SetRollbackVersion(system_state_->request_params()->app_version()); | 
 | 326 | } | 
 | 327 |  | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 328 | void PayloadState::IncrementPayloadAttemptNumber() { | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 329 |   // Update the payload attempt number for both payload types: full and delta. | 
 | 330 |   SetPayloadAttemptNumber(GetPayloadAttemptNumber() + 1); | 
| Alex Deymo | 29b51d9 | 2013-07-09 15:26:24 -0700 | [diff] [blame] | 331 |  | 
 | 332 |   // Report the metric every time the value is incremented. | 
 | 333 |   string metric = "Installer.PayloadAttemptNumber"; | 
 | 334 |   int value = GetPayloadAttemptNumber(); | 
 | 335 |  | 
 | 336 |   LOG(INFO) << "Uploading " << value << " (count) for metric " <<  metric; | 
 | 337 |   system_state_->metrics_lib()->SendToUMA( | 
 | 338 |        metric, | 
 | 339 |        value, | 
 | 340 |        1,    // min value | 
 | 341 |        50,   // max value | 
 | 342 |        kNumDefaultUmaBuckets); | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 343 | } | 
 | 344 |  | 
 | 345 | void PayloadState::IncrementFullPayloadAttemptNumber() { | 
 | 346 |   // Update the payload attempt number for full payloads and the backoff time. | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 347 |   if (response_.is_delta_payload) { | 
 | 348 |     LOG(INFO) << "Not incrementing payload attempt number for delta payloads"; | 
 | 349 |     return; | 
 | 350 |   } | 
 | 351 |  | 
| Alex Deymo | 29b51d9 | 2013-07-09 15:26:24 -0700 | [diff] [blame] | 352 |   LOG(INFO) << "Incrementing the full payload attempt number"; | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 353 |   SetFullPayloadAttemptNumber(GetFullPayloadAttemptNumber() + 1); | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 354 |   UpdateBackoffExpiryTime(); | 
| Alex Deymo | 29b51d9 | 2013-07-09 15:26:24 -0700 | [diff] [blame] | 355 |  | 
 | 356 |   // Report the metric every time the value is incremented. | 
 | 357 |   string metric = "Installer.FullPayloadAttemptNumber"; | 
 | 358 |   int value = GetFullPayloadAttemptNumber(); | 
 | 359 |  | 
 | 360 |   LOG(INFO) << "Uploading " << value << " (count) for metric " <<  metric; | 
 | 361 |   system_state_->metrics_lib()->SendToUMA( | 
 | 362 |        metric, | 
 | 363 |        value, | 
 | 364 |        1,    // min value | 
 | 365 |        50,   // max value | 
 | 366 |        kNumDefaultUmaBuckets); | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 367 | } | 
 | 368 |  | 
 | 369 | void PayloadState::IncrementUrlIndex() { | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 370 |   uint32_t next_url_index = GetUrlIndex() + 1; | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 371 |   if (next_url_index < candidate_urls_.size()) { | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 372 |     LOG(INFO) << "Incrementing the URL index for next attempt"; | 
 | 373 |     SetUrlIndex(next_url_index); | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 374 |   } else { | 
 | 375 |     LOG(INFO) << "Resetting the current URL index (" << GetUrlIndex() << ") to " | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 376 |               << "0 as we only have " << candidate_urls_.size() | 
 | 377 |               << " candidate URL(s)"; | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 378 |     SetUrlIndex(0); | 
| Alex Deymo | 29b51d9 | 2013-07-09 15:26:24 -0700 | [diff] [blame] | 379 |     IncrementPayloadAttemptNumber(); | 
 | 380 |     IncrementFullPayloadAttemptNumber(); | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 381 |   } | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 382 |  | 
| David Zeuthen | cc6f996 | 2013-04-18 11:57:24 -0700 | [diff] [blame] | 383 |   // If we have multiple URLs, record that we just switched to another one | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 384 |   if (candidate_urls_.size() > 1) | 
| David Zeuthen | cc6f996 | 2013-04-18 11:57:24 -0700 | [diff] [blame] | 385 |     SetUrlSwitchCount(url_switch_count_ + 1); | 
 | 386 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 387 |   // Whenever we update the URL index, we should also clear the URL failure | 
 | 388 |   // count so we can start over fresh for the new URL. | 
 | 389 |   SetUrlFailureCount(0); | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 390 | } | 
 | 391 |  | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 392 | void PayloadState::IncrementFailureCount() { | 
 | 393 |   uint32_t next_url_failure_count = GetUrlFailureCount() + 1; | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 394 |   if (next_url_failure_count < response_.max_failure_count_per_url) { | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 395 |     LOG(INFO) << "Incrementing the URL failure count"; | 
 | 396 |     SetUrlFailureCount(next_url_failure_count); | 
 | 397 |   } else { | 
 | 398 |     LOG(INFO) << "Reached max number of failures for Url" << GetUrlIndex() | 
 | 399 |               << ". Trying next available URL"; | 
 | 400 |     IncrementUrlIndex(); | 
 | 401 |   } | 
 | 402 | } | 
 | 403 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 404 | void PayloadState::UpdateBackoffExpiryTime() { | 
 | 405 |   if (response_.disable_payload_backoff) { | 
 | 406 |     LOG(INFO) << "Resetting backoff expiry time as payload backoff is disabled"; | 
 | 407 |     SetBackoffExpiryTime(Time()); | 
 | 408 |     return; | 
 | 409 |   } | 
 | 410 |  | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 411 |   if (GetFullPayloadAttemptNumber() == 0) { | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 412 |     SetBackoffExpiryTime(Time()); | 
 | 413 |     return; | 
 | 414 |   } | 
 | 415 |  | 
 | 416 |   // Since we're doing left-shift below, make sure we don't shift more | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 417 |   // than this. E.g. if int is 4-bytes, don't left-shift more than 30 bits, | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 418 |   // since we don't expect value of kMaxBackoffDays to be more than 100 anyway. | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 419 |   int num_days = 1; // the value to be shifted. | 
 | 420 |   const int kMaxShifts = (sizeof(num_days) * 8) - 2; | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 421 |  | 
 | 422 |   // Normal backoff days is 2 raised to (payload_attempt_number - 1). | 
 | 423 |   // E.g. if payload_attempt_number is over 30, limit power to 30. | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 424 |   int power = min(GetFullPayloadAttemptNumber() - 1, kMaxShifts); | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 425 |  | 
 | 426 |   // The number of days is the minimum of 2 raised to (payload_attempt_number | 
 | 427 |   // - 1) or kMaxBackoffDays. | 
 | 428 |   num_days = min(num_days << power, kMaxBackoffDays); | 
 | 429 |  | 
 | 430 |   // We don't want all retries to happen exactly at the same time when | 
 | 431 |   // retrying after backoff. So add some random minutes to fuzz. | 
 | 432 |   int fuzz_minutes = utils::FuzzInt(0, kMaxBackoffFuzzMinutes); | 
 | 433 |   TimeDelta next_backoff_interval = TimeDelta::FromDays(num_days) + | 
 | 434 |                                     TimeDelta::FromMinutes(fuzz_minutes); | 
 | 435 |   LOG(INFO) << "Incrementing the backoff expiry time by " | 
 | 436 |             << utils::FormatTimeDelta(next_backoff_interval); | 
 | 437 |   SetBackoffExpiryTime(Time::Now() + next_backoff_interval); | 
 | 438 | } | 
 | 439 |  | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 440 | void PayloadState::UpdateCurrentDownloadSource() { | 
 | 441 |   current_download_source_ = kNumDownloadSources; | 
 | 442 |  | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 443 |   if (GetUrlIndex() < candidate_urls_.size())  { | 
 | 444 |     string current_url = candidate_urls_[GetUrlIndex()]; | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 445 |     if (StartsWithASCII(current_url, "https://", false)) | 
 | 446 |       current_download_source_ = kDownloadSourceHttpsServer; | 
 | 447 |     else if (StartsWithASCII(current_url, "http://", false)) | 
 | 448 |       current_download_source_ = kDownloadSourceHttpServer; | 
 | 449 |   } | 
 | 450 |  | 
 | 451 |   LOG(INFO) << "Current download source: " | 
 | 452 |             << utils::ToString(current_download_source_); | 
 | 453 | } | 
 | 454 |  | 
 | 455 | void PayloadState::UpdateBytesDownloaded(size_t count) { | 
 | 456 |   SetCurrentBytesDownloaded( | 
 | 457 |       current_download_source_, | 
 | 458 |       GetCurrentBytesDownloaded(current_download_source_) + count, | 
 | 459 |       false); | 
 | 460 |   SetTotalBytesDownloaded( | 
 | 461 |       current_download_source_, | 
 | 462 |       GetTotalBytesDownloaded(current_download_source_) + count, | 
 | 463 |       false); | 
 | 464 | } | 
 | 465 |  | 
 | 466 | void PayloadState::ReportBytesDownloadedMetrics() { | 
 | 467 |   // Report metrics collected from all known download sources to UMA. | 
 | 468 |   // The reported data is in Megabytes in order to represent a larger | 
 | 469 |   // sample range. | 
| Jay Srinivasan | dbd9ea2 | 2013-04-22 17:45:19 -0700 | [diff] [blame] | 470 |   int download_sources_used = 0; | 
 | 471 |   string metric; | 
 | 472 |   uint64_t successful_mbs = 0; | 
 | 473 |   uint64_t total_mbs = 0; | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 474 |   for (int i = 0; i < kNumDownloadSources; i++) { | 
 | 475 |     DownloadSource source = static_cast<DownloadSource>(i); | 
 | 476 |     const int kMaxMiBs = 10240; // Anything above 10GB goes in the last bucket. | 
| David Zeuthen | 4484860 | 2013-06-24 13:32:14 -0700 | [diff] [blame] | 477 |     uint64_t mbs; | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 478 |  | 
| David Zeuthen | 4484860 | 2013-06-24 13:32:14 -0700 | [diff] [blame] | 479 |     // Only consider this download source (and send byte counts) as | 
 | 480 |     // having been used if we downloaded a non-trivial amount of bytes | 
 | 481 |     // (e.g. at least 1 MiB) that contributed to the final success of | 
 | 482 |     // the update. Otherwise we're going to end up with a lot of | 
 | 483 |     // zero-byte events in the histogram. | 
| Jay Srinivasan | dbd9ea2 | 2013-04-22 17:45:19 -0700 | [diff] [blame] | 484 |  | 
| David Zeuthen | 4484860 | 2013-06-24 13:32:14 -0700 | [diff] [blame] | 485 |     mbs = GetCurrentBytesDownloaded(source) / kNumBytesInOneMiB; | 
 | 486 |     if (mbs > 0) { | 
| Jay Srinivasan | dbd9ea2 | 2013-04-22 17:45:19 -0700 | [diff] [blame] | 487 |       download_sources_used |= (1 << source); | 
 | 488 |  | 
| David Zeuthen | 4484860 | 2013-06-24 13:32:14 -0700 | [diff] [blame] | 489 |       metric = "Installer.SuccessfulMBsDownloadedFrom" + | 
 | 490 |           utils::ToString(source); | 
 | 491 |       successful_mbs += mbs; | 
 | 492 |       LOG(INFO) << "Uploading " << mbs << " (MBs) for metric " << metric; | 
 | 493 |       system_state_->metrics_lib()->SendToUMA(metric, | 
 | 494 |                                               mbs, | 
 | 495 |                                               0,  // min | 
 | 496 |                                               kMaxMiBs, | 
 | 497 |                                               kNumDefaultUmaBuckets); | 
 | 498 |     } | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 499 |     SetCurrentBytesDownloaded(source, 0, true); | 
 | 500 |  | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 501 |     mbs = GetTotalBytesDownloaded(source) / kNumBytesInOneMiB; | 
| David Zeuthen | 4484860 | 2013-06-24 13:32:14 -0700 | [diff] [blame] | 502 |     if (mbs > 0) { | 
 | 503 |       metric = "Installer.TotalMBsDownloadedFrom" + utils::ToString(source); | 
 | 504 |       total_mbs += mbs; | 
 | 505 |       LOG(INFO) << "Uploading " << mbs << " (MBs) for metric " << metric; | 
 | 506 |       system_state_->metrics_lib()->SendToUMA(metric, | 
 | 507 |                                               mbs, | 
 | 508 |                                               0,  // min | 
 | 509 |                                               kMaxMiBs, | 
 | 510 |                                               kNumDefaultUmaBuckets); | 
 | 511 |     } | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 512 |     SetTotalBytesDownloaded(source, 0, true); | 
 | 513 |   } | 
| Jay Srinivasan | dbd9ea2 | 2013-04-22 17:45:19 -0700 | [diff] [blame] | 514 |  | 
 | 515 |   metric = "Installer.DownloadSourcesUsed"; | 
 | 516 |   LOG(INFO) << "Uploading 0x" << std::hex << download_sources_used | 
 | 517 |             << " (bit flags) for metric " << metric; | 
 | 518 |   int num_buckets = std::min(1 << kNumDownloadSources, kNumDefaultUmaBuckets); | 
 | 519 |   system_state_->metrics_lib()->SendToUMA(metric, | 
 | 520 |                                           download_sources_used, | 
 | 521 |                                           0,  // min | 
 | 522 |                                           1 << kNumDownloadSources, | 
 | 523 |                                           num_buckets); | 
 | 524 |  | 
 | 525 |   if (successful_mbs) { | 
 | 526 |     metric = "Installer.DownloadOverheadPercentage"; | 
 | 527 |     int percent_overhead = (total_mbs - successful_mbs) * 100 / successful_mbs; | 
 | 528 |     LOG(INFO) << "Uploading " << percent_overhead << "% for metric " << metric; | 
 | 529 |     system_state_->metrics_lib()->SendToUMA(metric, | 
 | 530 |                                             percent_overhead, | 
 | 531 |                                             0,    // min: 0% overhead | 
 | 532 |                                             1000, // max: 1000% overhead | 
 | 533 |                                             kNumDefaultUmaBuckets); | 
 | 534 |   } | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 535 | } | 
 | 536 |  | 
| David Zeuthen | cc6f996 | 2013-04-18 11:57:24 -0700 | [diff] [blame] | 537 | void PayloadState::ReportUpdateUrlSwitchesMetric() { | 
 | 538 |   string metric = "Installer.UpdateURLSwitches"; | 
 | 539 |   int value = static_cast<int>(url_switch_count_); | 
 | 540 |  | 
 | 541 |   LOG(INFO) << "Uploading " << value << " (count) for metric " <<  metric; | 
 | 542 |   system_state_->metrics_lib()->SendToUMA( | 
 | 543 |        metric, | 
 | 544 |        value, | 
 | 545 |        0,    // min value | 
 | 546 |        100,  // max value | 
 | 547 |        kNumDefaultUmaBuckets); | 
 | 548 | } | 
 | 549 |  | 
| Chris Sosa | be45bef | 2013-04-09 18:25:12 -0700 | [diff] [blame] | 550 | void PayloadState::ReportRebootMetrics() { | 
 | 551 |   // Report the number of num_reboots. | 
 | 552 |   string metric = "Installer.UpdateNumReboots"; | 
 | 553 |   uint32_t num_reboots = GetNumReboots(); | 
 | 554 |   LOG(INFO) << "Uploading reboot count of " << num_reboots << " for metric " | 
 | 555 |             <<  metric; | 
 | 556 |   system_state_->metrics_lib()->SendToUMA( | 
 | 557 |       metric, | 
 | 558 |       static_cast<int>(num_reboots),  // sample | 
 | 559 |       0,  // min = 0. | 
 | 560 |       50,  // max | 
 | 561 |       25);  // buckets | 
 | 562 |   SetNumReboots(0); | 
 | 563 | } | 
 | 564 |  | 
 | 565 | void PayloadState::UpdateNumReboots() { | 
 | 566 |   // We only update the reboot count when the system has been detected to have | 
 | 567 |   // been rebooted. | 
 | 568 |   if (!system_state_->system_rebooted()) { | 
 | 569 |     return; | 
 | 570 |   } | 
 | 571 |  | 
 | 572 |   SetNumReboots(GetNumReboots() + 1); | 
 | 573 | } | 
 | 574 |  | 
 | 575 | void PayloadState::SetNumReboots(uint32_t num_reboots) { | 
 | 576 |   CHECK(prefs_); | 
 | 577 |   num_reboots_ = num_reboots; | 
 | 578 |   prefs_->SetInt64(kPrefsNumReboots, num_reboots); | 
 | 579 |   LOG(INFO) << "Number of Reboots during current update attempt = " | 
 | 580 |             << num_reboots_; | 
 | 581 | } | 
 | 582 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 583 | void PayloadState::ResetPersistedState() { | 
 | 584 |   SetPayloadAttemptNumber(0); | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 585 |   SetFullPayloadAttemptNumber(0); | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 586 |   SetUrlIndex(0); | 
 | 587 |   SetUrlFailureCount(0); | 
| David Zeuthen | cc6f996 | 2013-04-18 11:57:24 -0700 | [diff] [blame] | 588 |   SetUrlSwitchCount(0); | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 589 |   UpdateBackoffExpiryTime(); // This will reset the backoff expiry time. | 
| David Zeuthen | f413fe5 | 2013-04-22 14:04:39 -0700 | [diff] [blame] | 590 |   SetUpdateTimestampStart(system_state_->clock()->GetWallclockTime()); | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 591 |   SetUpdateTimestampEnd(Time()); // Set to null time | 
 | 592 |   SetUpdateDurationUptime(TimeDelta::FromSeconds(0)); | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 593 |   ResetDownloadSourcesOnNewUpdate(); | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 594 |   ResetRollbackVersion(); | 
 | 595 | } | 
 | 596 |  | 
 | 597 | void PayloadState::ResetRollbackVersion() { | 
 | 598 |   CHECK(powerwash_safe_prefs_); | 
 | 599 |   rollback_version_ = ""; | 
 | 600 |   powerwash_safe_prefs_->Delete(kPrefsRollbackVersion); | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 601 | } | 
 | 602 |  | 
 | 603 | void PayloadState::ResetDownloadSourcesOnNewUpdate() { | 
 | 604 |   for (int i = 0; i < kNumDownloadSources; i++) { | 
 | 605 |     DownloadSource source = static_cast<DownloadSource>(i); | 
 | 606 |     SetCurrentBytesDownloaded(source, 0, true); | 
 | 607 |     // Note: Not resetting the TotalBytesDownloaded as we want that metric | 
 | 608 |     // to count the bytes downloaded across various update attempts until | 
 | 609 |     // we have successfully applied the update. | 
 | 610 |   } | 
 | 611 | } | 
 | 612 |  | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 613 | int64_t PayloadState::GetPersistedValue(const string& key, | 
 | 614 |                                         bool across_powerwash) { | 
 | 615 |   PrefsInterface* prefs = prefs_; | 
 | 616 |   if (across_powerwash) | 
 | 617 |     prefs = powerwash_safe_prefs_; | 
 | 618 |  | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 619 |   CHECK(prefs_); | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 620 |   if (!prefs->Exists(key)) | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 621 |     return 0; | 
 | 622 |  | 
 | 623 |   int64_t stored_value; | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 624 |   if (!prefs->GetInt64(key, &stored_value)) | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 625 |     return 0; | 
 | 626 |  | 
 | 627 |   if (stored_value < 0) { | 
 | 628 |     LOG(ERROR) << key << ": Invalid value (" << stored_value | 
 | 629 |                << ") in persisted state. Defaulting to 0"; | 
 | 630 |     return 0; | 
 | 631 |   } | 
 | 632 |  | 
 | 633 |   return stored_value; | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 634 | } | 
 | 635 |  | 
 | 636 | string PayloadState::CalculateResponseSignature() { | 
 | 637 |   string response_sign = StringPrintf("NumURLs = %d\n", | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 638 |                                       candidate_urls_.size()); | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 639 |  | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 640 |   for (size_t i = 0; i < candidate_urls_.size(); i++) | 
 | 641 |     response_sign += StringPrintf("Candidate Url%d = %s\n", | 
 | 642 |                                   i, candidate_urls_[i].c_str()); | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 643 |  | 
 | 644 |   response_sign += StringPrintf("Payload Size = %llu\n" | 
 | 645 |                                 "Payload Sha256 Hash = %s\n" | 
 | 646 |                                 "Metadata Size = %llu\n" | 
 | 647 |                                 "Metadata Signature = %s\n" | 
 | 648 |                                 "Is Delta Payload = %d\n" | 
 | 649 |                                 "Max Failure Count Per Url = %d\n" | 
 | 650 |                                 "Disable Payload Backoff = %d\n", | 
 | 651 |                                 response_.size, | 
 | 652 |                                 response_.hash.c_str(), | 
 | 653 |                                 response_.metadata_size, | 
 | 654 |                                 response_.metadata_signature.c_str(), | 
 | 655 |                                 response_.is_delta_payload, | 
 | 656 |                                 response_.max_failure_count_per_url, | 
 | 657 |                                 response_.disable_payload_backoff); | 
 | 658 |   return response_sign; | 
 | 659 | } | 
 | 660 |  | 
 | 661 | void PayloadState::LoadResponseSignature() { | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 662 |   CHECK(prefs_); | 
 | 663 |   string stored_value; | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 664 |   if (prefs_->Exists(kPrefsCurrentResponseSignature) && | 
 | 665 |       prefs_->GetString(kPrefsCurrentResponseSignature, &stored_value)) { | 
 | 666 |     SetResponseSignature(stored_value); | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 667 |   } | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 668 | } | 
 | 669 |  | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 670 | void PayloadState::SetResponseSignature(const string& response_signature) { | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 671 |   CHECK(prefs_); | 
 | 672 |   response_signature_ = response_signature; | 
 | 673 |   LOG(INFO) << "Current Response Signature = \n" << response_signature_; | 
 | 674 |   prefs_->SetString(kPrefsCurrentResponseSignature, response_signature_); | 
 | 675 | } | 
 | 676 |  | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 677 | void PayloadState::LoadPayloadAttemptNumber() { | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 678 |   SetPayloadAttemptNumber(GetPersistedValue(kPrefsPayloadAttemptNumber, | 
 | 679 |                                             false)); | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 680 | } | 
 | 681 |  | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 682 | void PayloadState::LoadFullPayloadAttemptNumber() { | 
 | 683 |   SetFullPayloadAttemptNumber(GetPersistedValue(kPrefsFullPayloadAttemptNumber, | 
 | 684 |                                             false)); | 
 | 685 | } | 
 | 686 |  | 
 | 687 | void PayloadState::SetPayloadAttemptNumber(int payload_attempt_number) { | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 688 |   CHECK(prefs_); | 
 | 689 |   payload_attempt_number_ = payload_attempt_number; | 
 | 690 |   LOG(INFO) << "Payload Attempt Number = " << payload_attempt_number_; | 
 | 691 |   prefs_->SetInt64(kPrefsPayloadAttemptNumber, payload_attempt_number_); | 
 | 692 | } | 
 | 693 |  | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 694 | void PayloadState::SetFullPayloadAttemptNumber( | 
 | 695 |     int full_payload_attempt_number) { | 
 | 696 |   CHECK(prefs_); | 
 | 697 |   full_payload_attempt_number_ = full_payload_attempt_number; | 
 | 698 |   LOG(INFO) << "Full Payload Attempt Number = " << full_payload_attempt_number_; | 
 | 699 |   prefs_->SetInt64(kPrefsFullPayloadAttemptNumber, | 
 | 700 |       full_payload_attempt_number_); | 
 | 701 | } | 
 | 702 |  | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 703 | void PayloadState::LoadUrlIndex() { | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 704 |   SetUrlIndex(GetPersistedValue(kPrefsCurrentUrlIndex, false)); | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 705 | } | 
 | 706 |  | 
 | 707 | void PayloadState::SetUrlIndex(uint32_t url_index) { | 
 | 708 |   CHECK(prefs_); | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 709 |   url_index_ = url_index; | 
 | 710 |   LOG(INFO) << "Current URL Index = " << url_index_; | 
 | 711 |   prefs_->SetInt64(kPrefsCurrentUrlIndex, url_index_); | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 712 |  | 
 | 713 |   // Also update the download source, which is purely dependent on the | 
 | 714 |   // current URL index alone. | 
 | 715 |   UpdateCurrentDownloadSource(); | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 716 | } | 
 | 717 |  | 
| David Zeuthen | cc6f996 | 2013-04-18 11:57:24 -0700 | [diff] [blame] | 718 | void PayloadState::LoadUrlSwitchCount() { | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 719 |   SetUrlSwitchCount(GetPersistedValue(kPrefsUrlSwitchCount, false)); | 
| David Zeuthen | cc6f996 | 2013-04-18 11:57:24 -0700 | [diff] [blame] | 720 | } | 
 | 721 |  | 
 | 722 | void PayloadState::SetUrlSwitchCount(uint32_t url_switch_count) { | 
 | 723 |   CHECK(prefs_); | 
 | 724 |   url_switch_count_ = url_switch_count; | 
 | 725 |   LOG(INFO) << "URL Switch Count = " << url_switch_count_; | 
 | 726 |   prefs_->SetInt64(kPrefsUrlSwitchCount, url_switch_count_); | 
 | 727 | } | 
 | 728 |  | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 729 | void PayloadState::LoadUrlFailureCount() { | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 730 |   SetUrlFailureCount(GetPersistedValue(kPrefsCurrentUrlFailureCount, | 
 | 731 |                                        false)); | 
| Jay Srinivasan | 2b5a0f0 | 2012-12-19 17:25:56 -0800 | [diff] [blame] | 732 | } | 
 | 733 |  | 
 | 734 | void PayloadState::SetUrlFailureCount(uint32_t url_failure_count) { | 
 | 735 |   CHECK(prefs_); | 
 | 736 |   url_failure_count_ = url_failure_count; | 
 | 737 |   LOG(INFO) << "Current URL (Url" << GetUrlIndex() | 
 | 738 |             << ")'s Failure Count = " << url_failure_count_; | 
 | 739 |   prefs_->SetInt64(kPrefsCurrentUrlFailureCount, url_failure_count_); | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 740 | } | 
 | 741 |  | 
| Jay Srinivasan | 0826288 | 2012-12-28 19:29:43 -0800 | [diff] [blame] | 742 | void PayloadState::LoadBackoffExpiryTime() { | 
 | 743 |   CHECK(prefs_); | 
 | 744 |   int64_t stored_value; | 
 | 745 |   if (!prefs_->Exists(kPrefsBackoffExpiryTime)) | 
 | 746 |     return; | 
 | 747 |  | 
 | 748 |   if (!prefs_->GetInt64(kPrefsBackoffExpiryTime, &stored_value)) | 
 | 749 |     return; | 
 | 750 |  | 
 | 751 |   Time stored_time = Time::FromInternalValue(stored_value); | 
 | 752 |   if (stored_time > Time::Now() + TimeDelta::FromDays(kMaxBackoffDays)) { | 
 | 753 |     LOG(ERROR) << "Invalid backoff expiry time (" | 
 | 754 |                << utils::ToString(stored_time) | 
 | 755 |                << ") in persisted state. Resetting."; | 
 | 756 |     stored_time = Time(); | 
 | 757 |   } | 
 | 758 |   SetBackoffExpiryTime(stored_time); | 
 | 759 | } | 
 | 760 |  | 
 | 761 | void PayloadState::SetBackoffExpiryTime(const Time& new_time) { | 
 | 762 |   CHECK(prefs_); | 
 | 763 |   backoff_expiry_time_ = new_time; | 
 | 764 |   LOG(INFO) << "Backoff Expiry Time = " | 
 | 765 |             << utils::ToString(backoff_expiry_time_); | 
 | 766 |   prefs_->SetInt64(kPrefsBackoffExpiryTime, | 
 | 767 |                    backoff_expiry_time_.ToInternalValue()); | 
 | 768 | } | 
 | 769 |  | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 770 | TimeDelta PayloadState::GetUpdateDuration() { | 
| David Zeuthen | f413fe5 | 2013-04-22 14:04:39 -0700 | [diff] [blame] | 771 |   Time end_time = update_timestamp_end_.is_null() | 
 | 772 |     ? system_state_->clock()->GetWallclockTime() : | 
 | 773 |       update_timestamp_end_; | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 774 |   return end_time - update_timestamp_start_; | 
 | 775 | } | 
 | 776 |  | 
 | 777 | void PayloadState::LoadUpdateTimestampStart() { | 
 | 778 |   int64_t stored_value; | 
 | 779 |   Time stored_time; | 
 | 780 |  | 
 | 781 |   CHECK(prefs_); | 
 | 782 |  | 
| David Zeuthen | f413fe5 | 2013-04-22 14:04:39 -0700 | [diff] [blame] | 783 |   Time now = system_state_->clock()->GetWallclockTime(); | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 784 |  | 
 | 785 |   if (!prefs_->Exists(kPrefsUpdateTimestampStart)) { | 
 | 786 |     // The preference missing is not unexpected - in that case, just | 
 | 787 |     // use the current time as start time | 
 | 788 |     stored_time = now; | 
 | 789 |   } else if (!prefs_->GetInt64(kPrefsUpdateTimestampStart, &stored_value)) { | 
 | 790 |     LOG(ERROR) << "Invalid UpdateTimestampStart value. Resetting."; | 
 | 791 |     stored_time = now; | 
 | 792 |   } else { | 
 | 793 |     stored_time = Time::FromInternalValue(stored_value); | 
 | 794 |   } | 
 | 795 |  | 
 | 796 |   // Sanity check: If the time read from disk is in the future | 
 | 797 |   // (modulo some slack to account for possible NTP drift | 
 | 798 |   // adjustments), something is fishy and we should report and | 
 | 799 |   // reset. | 
 | 800 |   TimeDelta duration_according_to_stored_time = now - stored_time; | 
 | 801 |   if (duration_according_to_stored_time < -kDurationSlack) { | 
 | 802 |     LOG(ERROR) << "The UpdateTimestampStart value (" | 
 | 803 |                << utils::ToString(stored_time) | 
 | 804 |                << ") in persisted state is " | 
| David Zeuthen | 674c318 | 2013-04-18 14:05:20 -0700 | [diff] [blame] | 805 |                << utils::FormatTimeDelta(duration_according_to_stored_time) | 
 | 806 |                << " in the future. Resetting."; | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 807 |     stored_time = now; | 
 | 808 |   } | 
 | 809 |  | 
 | 810 |   SetUpdateTimestampStart(stored_time); | 
 | 811 | } | 
 | 812 |  | 
 | 813 | void PayloadState::SetUpdateTimestampStart(const Time& value) { | 
 | 814 |   CHECK(prefs_); | 
 | 815 |   update_timestamp_start_ = value; | 
 | 816 |   prefs_->SetInt64(kPrefsUpdateTimestampStart, | 
 | 817 |                    update_timestamp_start_.ToInternalValue()); | 
 | 818 |   LOG(INFO) << "Update Timestamp Start = " | 
 | 819 |             << utils::ToString(update_timestamp_start_); | 
 | 820 | } | 
 | 821 |  | 
 | 822 | void PayloadState::SetUpdateTimestampEnd(const Time& value) { | 
 | 823 |   update_timestamp_end_ = value; | 
 | 824 |   LOG(INFO) << "Update Timestamp End = " | 
 | 825 |             << utils::ToString(update_timestamp_end_); | 
 | 826 | } | 
 | 827 |  | 
 | 828 | TimeDelta PayloadState::GetUpdateDurationUptime() { | 
 | 829 |   return update_duration_uptime_; | 
 | 830 | } | 
 | 831 |  | 
 | 832 | void PayloadState::LoadUpdateDurationUptime() { | 
 | 833 |   int64_t stored_value; | 
 | 834 |   TimeDelta stored_delta; | 
 | 835 |  | 
 | 836 |   CHECK(prefs_); | 
 | 837 |  | 
 | 838 |   if (!prefs_->Exists(kPrefsUpdateDurationUptime)) { | 
 | 839 |     // The preference missing is not unexpected - in that case, just | 
 | 840 |     // we'll use zero as the delta | 
 | 841 |   } else if (!prefs_->GetInt64(kPrefsUpdateDurationUptime, &stored_value)) { | 
 | 842 |     LOG(ERROR) << "Invalid UpdateDurationUptime value. Resetting."; | 
 | 843 |     stored_delta = TimeDelta::FromSeconds(0); | 
 | 844 |   } else { | 
 | 845 |     stored_delta = TimeDelta::FromInternalValue(stored_value); | 
 | 846 |   } | 
 | 847 |  | 
 | 848 |   // Sanity-check: Uptime can never be greater than the wall-clock | 
 | 849 |   // difference (modulo some slack). If it is, report and reset | 
 | 850 |   // to the wall-clock difference. | 
 | 851 |   TimeDelta diff = GetUpdateDuration() - stored_delta; | 
 | 852 |   if (diff < -kDurationSlack) { | 
 | 853 |     LOG(ERROR) << "The UpdateDurationUptime value (" | 
| David Zeuthen | 674c318 | 2013-04-18 14:05:20 -0700 | [diff] [blame] | 854 |                << utils::FormatTimeDelta(stored_delta) | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 855 |                << ") in persisted state is " | 
| David Zeuthen | 674c318 | 2013-04-18 14:05:20 -0700 | [diff] [blame] | 856 |                << utils::FormatTimeDelta(diff) | 
 | 857 |                << " larger than the wall-clock delta. Resetting."; | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 858 |     stored_delta = update_duration_current_; | 
 | 859 |   } | 
 | 860 |  | 
 | 861 |   SetUpdateDurationUptime(stored_delta); | 
 | 862 | } | 
 | 863 |  | 
| Chris Sosa | be45bef | 2013-04-09 18:25:12 -0700 | [diff] [blame] | 864 | void PayloadState::LoadNumReboots() { | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 865 |   SetNumReboots(GetPersistedValue(kPrefsNumReboots, false)); | 
 | 866 | } | 
 | 867 |  | 
 | 868 | void PayloadState::LoadRollbackVersion() { | 
 | 869 |   SetNumReboots(GetPersistedValue(kPrefsRollbackVersion, true)); | 
 | 870 | } | 
 | 871 |  | 
 | 872 | void PayloadState::SetRollbackVersion(const string& rollback_version) { | 
 | 873 |   CHECK(powerwash_safe_prefs_); | 
 | 874 |   LOG(INFO) << "Blacklisting version "<< rollback_version; | 
 | 875 |   rollback_version_ = rollback_version; | 
 | 876 |   powerwash_safe_prefs_->SetString(kPrefsRollbackVersion, rollback_version); | 
| Chris Sosa | be45bef | 2013-04-09 18:25:12 -0700 | [diff] [blame] | 877 | } | 
 | 878 |  | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 879 | void PayloadState::SetUpdateDurationUptimeExtended(const TimeDelta& value, | 
 | 880 |                                                    const Time& timestamp, | 
 | 881 |                                                    bool use_logging) { | 
 | 882 |   CHECK(prefs_); | 
 | 883 |   update_duration_uptime_ = value; | 
 | 884 |   update_duration_uptime_timestamp_ = timestamp; | 
 | 885 |   prefs_->SetInt64(kPrefsUpdateDurationUptime, | 
 | 886 |                    update_duration_uptime_.ToInternalValue()); | 
 | 887 |   if (use_logging) { | 
 | 888 |     LOG(INFO) << "Update Duration Uptime = " | 
| David Zeuthen | 674c318 | 2013-04-18 14:05:20 -0700 | [diff] [blame] | 889 |               << utils::FormatTimeDelta(update_duration_uptime_); | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 890 |   } | 
 | 891 | } | 
 | 892 |  | 
 | 893 | void PayloadState::SetUpdateDurationUptime(const TimeDelta& value) { | 
| David Zeuthen | f413fe5 | 2013-04-22 14:04:39 -0700 | [diff] [blame] | 894 |   Time now = system_state_->clock()->GetMonotonicTime(); | 
 | 895 |   SetUpdateDurationUptimeExtended(value, now, true); | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 896 | } | 
 | 897 |  | 
 | 898 | void PayloadState::CalculateUpdateDurationUptime() { | 
| David Zeuthen | f413fe5 | 2013-04-22 14:04:39 -0700 | [diff] [blame] | 899 |   Time now = system_state_->clock()->GetMonotonicTime(); | 
| David Zeuthen | 9a017f2 | 2013-04-11 16:10:26 -0700 | [diff] [blame] | 900 |   TimeDelta uptime_since_last_update = now - update_duration_uptime_timestamp_; | 
 | 901 |   TimeDelta new_uptime = update_duration_uptime_ + uptime_since_last_update; | 
 | 902 |   // We're frequently called so avoid logging this write | 
 | 903 |   SetUpdateDurationUptimeExtended(new_uptime, now, false); | 
 | 904 | } | 
 | 905 |  | 
| David Zeuthen | 674c318 | 2013-04-18 14:05:20 -0700 | [diff] [blame] | 906 | void PayloadState::ReportDurationMetrics() { | 
 | 907 |   TimeDelta duration = GetUpdateDuration(); | 
 | 908 |   TimeDelta duration_uptime = GetUpdateDurationUptime(); | 
 | 909 |   string metric; | 
 | 910 |  | 
 | 911 |   metric = "Installer.UpdateDurationMinutes"; | 
 | 912 |   system_state_->metrics_lib()->SendToUMA( | 
 | 913 |        metric, | 
 | 914 |        static_cast<int>(duration.InMinutes()), | 
 | 915 |        1,             // min: 1 minute | 
 | 916 |        365*24*60,     // max: 1 year (approx) | 
 | 917 |        kNumDefaultUmaBuckets); | 
 | 918 |   LOG(INFO) << "Uploading " << utils::FormatTimeDelta(duration) | 
 | 919 |             << " for metric " <<  metric; | 
 | 920 |  | 
 | 921 |   metric = "Installer.UpdateDurationUptimeMinutes"; | 
 | 922 |   system_state_->metrics_lib()->SendToUMA( | 
 | 923 |        metric, | 
 | 924 |        static_cast<int>(duration_uptime.InMinutes()), | 
 | 925 |        1,             // min: 1 minute | 
 | 926 |        30*24*60,      // max: 1 month (approx) | 
 | 927 |        kNumDefaultUmaBuckets); | 
 | 928 |   LOG(INFO) << "Uploading " << utils::FormatTimeDelta(duration_uptime) | 
 | 929 |             << " for metric " <<  metric; | 
 | 930 |  | 
 | 931 |   prefs_->Delete(kPrefsUpdateTimestampStart); | 
 | 932 |   prefs_->Delete(kPrefsUpdateDurationUptime); | 
 | 933 | } | 
 | 934 |  | 
| Alex Deymo | 1c656c4 | 2013-06-28 11:02:14 -0700 | [diff] [blame] | 935 | void PayloadState::ReportPayloadTypeMetric() { | 
 | 936 |   string metric; | 
 | 937 |   PayloadType uma_payload_type; | 
 | 938 |   OmahaRequestParams* params = system_state_->request_params(); | 
 | 939 |  | 
 | 940 |   if (response_.is_delta_payload) { | 
 | 941 |     uma_payload_type = kPayloadTypeDelta; | 
 | 942 |   } else if (params->delta_okay()) { | 
 | 943 |     uma_payload_type = kPayloadTypeFull; | 
 | 944 |   } else { // Full payload, delta was not allowed by request. | 
 | 945 |     uma_payload_type = kPayloadTypeForcedFull; | 
 | 946 |   } | 
 | 947 |  | 
 | 948 |   metric = "Installer.PayloadFormat"; | 
 | 949 |   system_state_->metrics_lib()->SendEnumToUMA( | 
 | 950 |       metric, | 
 | 951 |       uma_payload_type, | 
 | 952 |       kNumPayloadTypes); | 
 | 953 |   LOG(INFO) << "Uploading " << utils::ToString(uma_payload_type) | 
 | 954 |             << " for metric " <<  metric; | 
 | 955 | } | 
 | 956 |  | 
| Alex Deymo | 820cc70 | 2013-06-28 15:43:46 -0700 | [diff] [blame] | 957 | void PayloadState::ReportAttemptsCountMetrics() { | 
 | 958 |   string metric; | 
 | 959 |   int total_attempts = GetPayloadAttemptNumber(); | 
 | 960 |  | 
 | 961 |   metric = "Installer.AttemptsCount.Total"; | 
 | 962 |   system_state_->metrics_lib()->SendToUMA( | 
 | 963 |        metric, | 
 | 964 |        total_attempts, | 
 | 965 |        1,      // min | 
 | 966 |        50,     // max | 
 | 967 |        kNumDefaultUmaBuckets); | 
 | 968 |   LOG(INFO) << "Uploading " << total_attempts | 
 | 969 |             << " for metric " <<  metric; | 
 | 970 | } | 
 | 971 |  | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 972 | string PayloadState::GetPrefsKey(const string& prefix, DownloadSource source) { | 
 | 973 |   return prefix + "-from-" + utils::ToString(source); | 
 | 974 | } | 
 | 975 |  | 
 | 976 | void PayloadState::LoadCurrentBytesDownloaded(DownloadSource source) { | 
 | 977 |   string key = GetPrefsKey(kPrefsCurrentBytesDownloaded, source); | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 978 |   SetCurrentBytesDownloaded(source, GetPersistedValue(key, false), true); | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 979 | } | 
 | 980 |  | 
 | 981 | void PayloadState::SetCurrentBytesDownloaded( | 
 | 982 |     DownloadSource source, | 
 | 983 |     uint64_t current_bytes_downloaded, | 
 | 984 |     bool log) { | 
 | 985 |   CHECK(prefs_); | 
 | 986 |  | 
 | 987 |   if (source >= kNumDownloadSources) | 
 | 988 |     return; | 
 | 989 |  | 
 | 990 |   // Update the in-memory value. | 
 | 991 |   current_bytes_downloaded_[source] = current_bytes_downloaded; | 
 | 992 |  | 
 | 993 |   string prefs_key = GetPrefsKey(kPrefsCurrentBytesDownloaded, source); | 
 | 994 |   prefs_->SetInt64(prefs_key, current_bytes_downloaded); | 
 | 995 |   LOG_IF(INFO, log) << "Current bytes downloaded for " | 
 | 996 |                     << utils::ToString(source) << " = " | 
 | 997 |                     << GetCurrentBytesDownloaded(source); | 
 | 998 | } | 
 | 999 |  | 
 | 1000 | void PayloadState::LoadTotalBytesDownloaded(DownloadSource source) { | 
 | 1001 |   string key = GetPrefsKey(kPrefsTotalBytesDownloaded, source); | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 1002 |   SetTotalBytesDownloaded(source, GetPersistedValue(key, false), true); | 
| Jay Srinivasan | 19409b7 | 2013-04-12 19:23:36 -0700 | [diff] [blame] | 1003 | } | 
 | 1004 |  | 
 | 1005 | void PayloadState::SetTotalBytesDownloaded( | 
 | 1006 |     DownloadSource source, | 
 | 1007 |     uint64_t total_bytes_downloaded, | 
 | 1008 |     bool log) { | 
 | 1009 |   CHECK(prefs_); | 
 | 1010 |  | 
 | 1011 |   if (source >= kNumDownloadSources) | 
 | 1012 |     return; | 
 | 1013 |  | 
 | 1014 |   // Update the in-memory value. | 
 | 1015 |   total_bytes_downloaded_[source] = total_bytes_downloaded; | 
 | 1016 |  | 
 | 1017 |   // Persist. | 
 | 1018 |   string prefs_key = GetPrefsKey(kPrefsTotalBytesDownloaded, source); | 
 | 1019 |   prefs_->SetInt64(prefs_key, total_bytes_downloaded); | 
 | 1020 |   LOG_IF(INFO, log) << "Total bytes downloaded for " | 
 | 1021 |                     << utils::ToString(source) << " = " | 
 | 1022 |                     << GetTotalBytesDownloaded(source); | 
 | 1023 | } | 
 | 1024 |  | 
| David Zeuthen | a573d6f | 2013-06-14 16:13:36 -0700 | [diff] [blame] | 1025 | void PayloadState::LoadNumResponsesSeen() { | 
| Chris Sosa | aa18e16 | 2013-06-20 13:20:30 -0700 | [diff] [blame] | 1026 |   SetNumResponsesSeen(GetPersistedValue(kPrefsNumResponsesSeen, false)); | 
| David Zeuthen | a573d6f | 2013-06-14 16:13:36 -0700 | [diff] [blame] | 1027 | } | 
 | 1028 |  | 
 | 1029 | void PayloadState::SetNumResponsesSeen(int num_responses_seen) { | 
 | 1030 |   CHECK(prefs_); | 
 | 1031 |   num_responses_seen_ = num_responses_seen; | 
 | 1032 |   LOG(INFO) << "Num Responses Seen = " << num_responses_seen_; | 
 | 1033 |   prefs_->SetInt64(kPrefsNumResponsesSeen, num_responses_seen_); | 
 | 1034 | } | 
 | 1035 |  | 
 | 1036 | void PayloadState::ReportUpdatesAbandonedCountMetric() { | 
 | 1037 |   string metric = "Installer.UpdatesAbandonedCount"; | 
 | 1038 |   int value = num_responses_seen_ - 1; | 
 | 1039 |  | 
 | 1040 |   LOG(INFO) << "Uploading " << value << " (count) for metric " <<  metric; | 
 | 1041 |   system_state_->metrics_lib()->SendToUMA( | 
 | 1042 |        metric, | 
 | 1043 |        value, | 
 | 1044 |        0,    // min value | 
 | 1045 |        100,  // max value | 
 | 1046 |        kNumDefaultUmaBuckets); | 
 | 1047 | } | 
 | 1048 |  | 
| Alex Deymo | b33b0f0 | 2013-08-08 21:10:02 -0700 | [diff] [blame] | 1049 | void PayloadState::ReportUpdatesAbandonedEventCountMetric() { | 
 | 1050 |   string metric = "Installer.UpdatesAbandonedEventCount"; | 
 | 1051 |   int value = num_responses_seen_ - 1; | 
 | 1052 |  | 
 | 1053 |   // Do not send an "abandoned" event when 0 payloads were abandoned since the | 
 | 1054 |   // last successful update. | 
 | 1055 |   if (value == 0) | 
 | 1056 |     return; | 
 | 1057 |  | 
 | 1058 |   LOG(INFO) << "Uploading " << value << " (count) for metric " <<  metric; | 
 | 1059 |   system_state_->metrics_lib()->SendToUMA( | 
 | 1060 |        metric, | 
 | 1061 |        value, | 
 | 1062 |        0,    // min value | 
 | 1063 |        100,  // max value | 
 | 1064 |        kNumDefaultUmaBuckets); | 
 | 1065 | } | 
 | 1066 |  | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 1067 | void PayloadState::ComputeCandidateUrls() { | 
| Chris Sosa | f7d8004 | 2013-08-22 16:45:17 -0700 | [diff] [blame^] | 1068 |   bool http_url_ok = true; | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 1069 |  | 
 | 1070 |   if (system_state_->IsOfficialBuild()) { | 
 | 1071 |     const policy::DevicePolicy* policy = system_state_->device_policy(); | 
| Chris Sosa | f7d8004 | 2013-08-22 16:45:17 -0700 | [diff] [blame^] | 1072 |     if (policy && policy->GetHttpDownloadsEnabled(&http_url_ok) && !http_url_ok) | 
| Jay Srinivasan | 53173b9 | 2013-05-17 17:13:01 -0700 | [diff] [blame] | 1073 |       LOG(INFO) << "Downloads via HTTP Url are not enabled by device policy"; | 
 | 1074 |   } else { | 
 | 1075 |     LOG(INFO) << "Allowing HTTP downloads for unofficial builds"; | 
 | 1076 |     http_url_ok = true; | 
 | 1077 |   } | 
 | 1078 |  | 
 | 1079 |   candidate_urls_.clear(); | 
 | 1080 |   for (size_t i = 0; i < response_.payload_urls.size(); i++) { | 
 | 1081 |     string candidate_url = response_.payload_urls[i]; | 
 | 1082 |     if (StartsWithASCII(candidate_url, "http://", false) && !http_url_ok) | 
 | 1083 |         continue; | 
 | 1084 |     candidate_urls_.push_back(candidate_url); | 
 | 1085 |     LOG(INFO) << "Candidate Url" << (candidate_urls_.size() - 1) | 
 | 1086 |               << ": " << candidate_url; | 
 | 1087 |   } | 
 | 1088 |  | 
 | 1089 |   LOG(INFO) << "Found " << candidate_urls_.size() << " candidate URLs " | 
 | 1090 |             << "out of " << response_.payload_urls.size() << " URLs supplied"; | 
 | 1091 | } | 
 | 1092 |  | 
| David Zeuthen | e4c58bf | 2013-06-18 17:26:50 -0700 | [diff] [blame] | 1093 | void PayloadState::CreateSystemUpdatedMarkerFile() { | 
 | 1094 |   CHECK(prefs_); | 
 | 1095 |   int64_t value = system_state_->clock()->GetWallclockTime().ToInternalValue(); | 
 | 1096 |   prefs_->SetInt64(kPrefsSystemUpdatedMarker, value); | 
 | 1097 | } | 
 | 1098 |  | 
 | 1099 | void PayloadState::BootedIntoUpdate(TimeDelta time_to_reboot) { | 
 | 1100 |   // Send |time_to_reboot| as a UMA stat. | 
 | 1101 |   string metric = "Installer.TimeToRebootMinutes"; | 
 | 1102 |   system_state_->metrics_lib()->SendToUMA(metric, | 
 | 1103 |                                           time_to_reboot.InMinutes(), | 
 | 1104 |                                           0,        // min: 0 minute | 
 | 1105 |                                           30*24*60, // max: 1 month (approx) | 
 | 1106 |                                           kNumDefaultUmaBuckets); | 
 | 1107 |   LOG(INFO) << "Uploading " << utils::FormatTimeDelta(time_to_reboot) | 
 | 1108 |             << " for metric " <<  metric; | 
 | 1109 | } | 
 | 1110 |  | 
 | 1111 | void PayloadState::UpdateEngineStarted() { | 
| Alex Deymo | 569c424 | 2013-07-24 12:01:01 -0700 | [diff] [blame] | 1112 |   // Avoid the UpdateEngineStarted actions if this is not the first time we | 
 | 1113 |   // run the update engine since reboot. | 
 | 1114 |   if (!system_state_->system_rebooted()) | 
 | 1115 |     return; | 
 | 1116 |  | 
| David Zeuthen | e4c58bf | 2013-06-18 17:26:50 -0700 | [diff] [blame] | 1117 |   // Figure out if we just booted into a new update | 
 | 1118 |   if (prefs_->Exists(kPrefsSystemUpdatedMarker)) { | 
 | 1119 |     int64_t stored_value; | 
 | 1120 |     if (prefs_->GetInt64(kPrefsSystemUpdatedMarker, &stored_value)) { | 
 | 1121 |       Time system_updated_at = Time::FromInternalValue(stored_value); | 
 | 1122 |       if (!system_updated_at.is_null()) { | 
 | 1123 |         TimeDelta time_to_reboot = | 
 | 1124 |             system_state_->clock()->GetWallclockTime() - system_updated_at; | 
 | 1125 |         if (time_to_reboot.ToInternalValue() < 0) { | 
 | 1126 |           LOG(ERROR) << "time_to_reboot is negative - system_updated_at: " | 
 | 1127 |                      << utils::ToString(system_updated_at); | 
 | 1128 |         } else { | 
 | 1129 |           BootedIntoUpdate(time_to_reboot); | 
 | 1130 |         } | 
 | 1131 |       } | 
 | 1132 |     } | 
 | 1133 |     prefs_->Delete(kPrefsSystemUpdatedMarker); | 
 | 1134 |   } | 
| Alex Deymo | 4243291 | 2013-07-12 20:21:15 -0700 | [diff] [blame] | 1135 |   // Check if it is needed to send metrics about a failed reboot into a new | 
 | 1136 |   // version. | 
 | 1137 |   ReportFailedBootIfNeeded(); | 
 | 1138 | } | 
 | 1139 |  | 
 | 1140 | void PayloadState::ReportFailedBootIfNeeded() { | 
 | 1141 |   // If the kPrefsTargetVersionInstalledFrom is present, a successfully applied | 
 | 1142 |   // payload was marked as ready immediately before the last reboot, and we | 
 | 1143 |   // need to check if such payload successfully rebooted or not. | 
 | 1144 |   if (prefs_->Exists(kPrefsTargetVersionInstalledFrom)) { | 
 | 1145 |     string installed_from; | 
 | 1146 |     if (!prefs_->GetString(kPrefsTargetVersionInstalledFrom, &installed_from)) { | 
 | 1147 |       LOG(ERROR) << "Error reading TargetVersionInstalledFrom on reboot."; | 
 | 1148 |       return; | 
 | 1149 |     } | 
 | 1150 |     if (installed_from == | 
 | 1151 |         utils::PartitionNumber(system_state_->hardware()->BootDevice())) { | 
 | 1152 |       // A reboot was pending, but the chromebook is again in the same | 
 | 1153 |       // BootDevice where the update was installed from. | 
 | 1154 |       int64_t target_attempt; | 
 | 1155 |       if (!prefs_->GetInt64(kPrefsTargetVersionAttempt, &target_attempt)) { | 
 | 1156 |         LOG(ERROR) << "Error reading TargetVersionAttempt when " | 
 | 1157 |                       "TargetVersionInstalledFrom was present."; | 
 | 1158 |         target_attempt = 1; | 
 | 1159 |       } | 
 | 1160 |  | 
 | 1161 |       // Report the UMA metric of the current boot failure. | 
 | 1162 |       string metric = "Installer.RebootToNewPartitionAttempt"; | 
 | 1163 |  | 
 | 1164 |       LOG(INFO) << "Uploading " << target_attempt | 
 | 1165 |                 << " (count) for metric " <<  metric; | 
 | 1166 |       system_state_->metrics_lib()->SendToUMA( | 
 | 1167 |            metric, | 
 | 1168 |            target_attempt, | 
 | 1169 |            1,    // min value | 
 | 1170 |            50,   // max value | 
 | 1171 |            kNumDefaultUmaBuckets); | 
 | 1172 |     } else { | 
 | 1173 |       prefs_->Delete(kPrefsTargetVersionAttempt); | 
 | 1174 |       prefs_->Delete(kPrefsTargetVersionUniqueId); | 
 | 1175 |     } | 
 | 1176 |     prefs_->Delete(kPrefsTargetVersionInstalledFrom); | 
 | 1177 |   } | 
 | 1178 | } | 
 | 1179 |  | 
 | 1180 | void PayloadState::ExpectRebootInNewVersion(const string& target_version_uid) { | 
 | 1181 |   // Expect to boot into the new partition in the next reboot setting the | 
 | 1182 |   // TargetVersion* flags in the Prefs. | 
 | 1183 |   string stored_target_version_uid; | 
 | 1184 |   string target_version_id; | 
 | 1185 |   string target_partition; | 
 | 1186 |   int64_t target_attempt; | 
 | 1187 |  | 
 | 1188 |   if (prefs_->Exists(kPrefsTargetVersionUniqueId) && | 
 | 1189 |       prefs_->GetString(kPrefsTargetVersionUniqueId, | 
 | 1190 |                         &stored_target_version_uid) && | 
 | 1191 |       stored_target_version_uid == target_version_uid) { | 
 | 1192 |     if (!prefs_->GetInt64(kPrefsTargetVersionAttempt, &target_attempt)) | 
 | 1193 |       target_attempt = 0; | 
 | 1194 |   } else { | 
 | 1195 |     prefs_->SetString(kPrefsTargetVersionUniqueId, target_version_uid); | 
 | 1196 |     target_attempt = 0; | 
 | 1197 |   } | 
 | 1198 |   prefs_->SetInt64(kPrefsTargetVersionAttempt, target_attempt + 1); | 
 | 1199 |  | 
 | 1200 |   prefs_->SetString(kPrefsTargetVersionInstalledFrom, | 
 | 1201 |                     utils::PartitionNumber( | 
 | 1202 |                         system_state_->hardware()->BootDevice())); | 
 | 1203 | } | 
 | 1204 |  | 
 | 1205 | void PayloadState::ResetUpdateStatus() { | 
 | 1206 |   // Remove the TargetVersionInstalledFrom pref so that if the machine is | 
 | 1207 |   // rebooted the next boot is not flagged as failed to rebooted into the | 
 | 1208 |   // new applied payload. | 
 | 1209 |   prefs_->Delete(kPrefsTargetVersionInstalledFrom); | 
 | 1210 |  | 
 | 1211 |   // Also decrement the attempt number if it exists. | 
 | 1212 |   int64_t target_attempt; | 
 | 1213 |   if (prefs_->GetInt64(kPrefsTargetVersionAttempt, &target_attempt)) | 
 | 1214 |     prefs_->SetInt64(kPrefsTargetVersionAttempt, target_attempt-1); | 
| David Zeuthen | e4c58bf | 2013-06-18 17:26:50 -0700 | [diff] [blame] | 1215 | } | 
 | 1216 |  | 
| Jay Srinivasan | 6f6ea00 | 2012-12-14 11:26:28 -0800 | [diff] [blame] | 1217 | }  // namespace chromeos_update_engine |