blob: 1699f64abc4192706310479b9a81e4516c1beb09 [file] [log] [blame]
Jay Srinivasan6f6ea002012-12-14 11:26:28 -08001// 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 Srinivasan08262882012-12-28 19:29:43 -08007#include <algorithm>
8
Jay Srinivasan6f6ea002012-12-14 11:26:28 -08009#include <base/logging.h>
10#include <base/stringprintf.h>
11
Jay Srinivasand29695d2013-04-08 15:08:05 -070012#include "update_engine/constants.h"
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -080013#include "update_engine/utils.h"
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080014
Jay Srinivasan08262882012-12-28 19:29:43 -080015using base::Time;
16using base::TimeDelta;
17using std::min;
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080018using std::string;
19
20namespace chromeos_update_engine {
21
David Zeuthen9a017f22013-04-11 16:10:26 -070022const TimeDelta PayloadState::kDurationSlack = TimeDelta::FromSeconds(600);
23
Jay Srinivasan08262882012-12-28 19:29:43 -080024// We want to upperbound backoffs to 16 days
25static const uint32_t kMaxBackoffDays = 16;
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080026
Jay Srinivasan08262882012-12-28 19:29:43 -080027// We want to randomize retry attempts after the backoff by +/- 6 hours.
28static const uint32_t kMaxBackoffFuzzMinutes = 12 * 60;
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080029
30bool PayloadState::Initialize(PrefsInterface* prefs) {
31 CHECK(prefs);
32 prefs_ = prefs;
Jay Srinivasan08262882012-12-28 19:29:43 -080033 LoadResponseSignature();
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -080034 LoadPayloadAttemptNumber();
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080035 LoadUrlIndex();
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -080036 LoadUrlFailureCount();
Jay Srinivasan08262882012-12-28 19:29:43 -080037 LoadBackoffExpiryTime();
David Zeuthen9a017f22013-04-11 16:10:26 -070038 LoadUpdateTimestampStart();
39 // The LoadUpdateDurationUptime() method relies on LoadUpdateTimestampStart()
40 // being called before it. Don't reorder.
41 LoadUpdateDurationUptime();
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080042 return true;
43}
44
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080045void PayloadState::SetResponse(const OmahaResponse& omaha_response) {
Jay Srinivasan08262882012-12-28 19:29:43 -080046 // Always store the latest response.
47 response_ = omaha_response;
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080048
Jay Srinivasan08262882012-12-28 19:29:43 -080049 // Check if the "signature" of this response (i.e. the fields we care about)
50 // has changed.
51 string new_response_signature = CalculateResponseSignature();
52 bool has_response_changed = (response_signature_ != new_response_signature);
53
54 // If the response has changed, we should persist the new signature and
55 // clear away all the existing state.
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080056 if (has_response_changed) {
Jay Srinivasan08262882012-12-28 19:29:43 -080057 LOG(INFO) << "Resetting all persisted state as this is a new response";
58 SetResponseSignature(new_response_signature);
59 ResetPersistedState();
60 return;
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -080061 }
62
Jay Srinivasan08262882012-12-28 19:29:43 -080063 // This is the earliest point at which we can validate whether the URL index
64 // we loaded from the persisted state is a valid value. If the response
65 // hasn't changed but the URL index is invalid, it's indicative of some
66 // tampering of the persisted state.
67 if (url_index_ >= GetNumUrls()) {
68 LOG(INFO) << "Resetting all payload state as the url index seems to have "
69 "been tampered with";
70 ResetPersistedState();
71 return;
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080072 }
73}
74
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -080075void PayloadState::DownloadComplete() {
76 LOG(INFO) << "Payload downloaded successfully";
77 IncrementPayloadAttemptNumber();
78}
79
80void PayloadState::DownloadProgress(size_t count) {
81 if (count == 0)
82 return;
83
David Zeuthen9a017f22013-04-11 16:10:26 -070084 CalculateUpdateDurationUptime();
85
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -080086 // We've received non-zero bytes from a recent download operation. Since our
87 // URL failure count is meant to penalize a URL only for consecutive
88 // failures, downloading bytes successfully means we should reset the failure
89 // count (as we know at least that the URL is working). In future, we can
90 // design this to be more sophisticated to check for more intelligent failure
91 // patterns, but right now, even 1 byte downloaded will mark the URL to be
92 // good unless it hits 10 (or configured number of) consecutive failures
93 // again.
94
95 if (GetUrlFailureCount() == 0)
96 return;
97
98 LOG(INFO) << "Resetting failure count of Url" << GetUrlIndex()
99 << " to 0 as we received " << count << " bytes successfully";
100 SetUrlFailureCount(0);
101}
102
David Zeuthen9a017f22013-04-11 16:10:26 -0700103void PayloadState::UpdateSucceeded() {
104 CalculateUpdateDurationUptime();
105 SetUpdateTimestampEnd(Time::Now());
106}
107
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800108void PayloadState::UpdateFailed(ActionExitCode error) {
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800109 ActionExitCode base_error = utils::GetBaseErrorCode(error);
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800110 LOG(INFO) << "Updating payload state for error code: " << base_error
111 << " (" << utils::CodeToString(base_error) << ")";
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800112
Jay Srinivasan08262882012-12-28 19:29:43 -0800113 if (GetNumUrls() == 0) {
114 // This means we got this error even before we got a valid Omaha response.
115 // So we should not advance the url_index_ in such cases.
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800116 LOG(INFO) << "Ignoring failures until we get a valid Omaha response.";
117 return;
118 }
119
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800120 switch (base_error) {
121 // Errors which are good indicators of a problem with a particular URL or
122 // the protocol used in the URL or entities in the communication channel
123 // (e.g. proxies). We should try the next available URL in the next update
124 // check to quickly recover from these errors.
125 case kActionCodePayloadHashMismatchError:
126 case kActionCodePayloadSizeMismatchError:
127 case kActionCodeDownloadPayloadVerificationError:
128 case kActionCodeDownloadPayloadPubKeyVerificationError:
129 case kActionCodeSignedDeltaPayloadExpectedError:
130 case kActionCodeDownloadInvalidMetadataMagicString:
131 case kActionCodeDownloadSignatureMissingInManifest:
132 case kActionCodeDownloadManifestParseError:
133 case kActionCodeDownloadMetadataSignatureError:
134 case kActionCodeDownloadMetadataSignatureVerificationError:
135 case kActionCodeDownloadMetadataSignatureMismatch:
136 case kActionCodeDownloadOperationHashVerificationError:
137 case kActionCodeDownloadOperationExecutionError:
138 case kActionCodeDownloadOperationHashMismatch:
139 case kActionCodeDownloadInvalidMetadataSize:
140 case kActionCodeDownloadInvalidMetadataSignature:
141 case kActionCodeDownloadOperationHashMissingError:
142 case kActionCodeDownloadMetadataSignatureMissingError:
143 IncrementUrlIndex();
144 break;
145
146 // Errors which seem to be just transient network/communication related
147 // failures and do not indicate any inherent problem with the URL itself.
148 // So, we should keep the current URL but just increment the
149 // failure count to give it more chances. This way, while we maximize our
150 // chances of downloading from the URLs that appear earlier in the response
151 // (because download from a local server URL that appears earlier in a
152 // response is preferable than downloading from the next URL which could be
153 // a internet URL and thus could be more expensive).
154 case kActionCodeError:
155 case kActionCodeDownloadTransferError:
156 case kActionCodeDownloadWriteError:
157 case kActionCodeDownloadStateInitializationError:
158 case kActionCodeOmahaErrorInHTTPResponse: // Aggregate code for HTTP errors.
159 IncrementFailureCount();
160 break;
161
162 // Errors which are not specific to a URL and hence shouldn't result in
163 // the URL being penalized. This can happen in two cases:
164 // 1. We haven't started downloading anything: These errors don't cost us
165 // anything in terms of actual payload bytes, so we should just do the
166 // regular retries at the next update check.
167 // 2. We have successfully downloaded the payload: In this case, the
168 // payload attempt number would have been incremented and would take care
Jay Srinivasan08262882012-12-28 19:29:43 -0800169 // of the backoff at the next update check.
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800170 // In either case, there's no need to update URL index or failure count.
171 case kActionCodeOmahaRequestError:
172 case kActionCodeOmahaResponseHandlerError:
173 case kActionCodePostinstallRunnerError:
174 case kActionCodeFilesystemCopierError:
175 case kActionCodeInstallDeviceOpenError:
176 case kActionCodeKernelDeviceOpenError:
177 case kActionCodeDownloadNewPartitionInfoError:
178 case kActionCodeNewRootfsVerificationError:
179 case kActionCodeNewKernelVerificationError:
180 case kActionCodePostinstallBootedFromFirmwareB:
181 case kActionCodeOmahaRequestEmptyResponseError:
182 case kActionCodeOmahaRequestXMLParseError:
183 case kActionCodeOmahaResponseInvalid:
184 case kActionCodeOmahaUpdateIgnoredPerPolicy:
185 case kActionCodeOmahaUpdateDeferredPerPolicy:
Jay Srinivasan08262882012-12-28 19:29:43 -0800186 case kActionCodeOmahaUpdateDeferredForBackoff:
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700187 case kActionCodePostinstallPowerwashError:
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700188 case kActionCodeUpdateCanceledByChannelChange:
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800189 LOG(INFO) << "Not incrementing URL index or failure count for this error";
190 break;
191
192 case kActionCodeSuccess: // success code
193 case kActionCodeSetBootableFlagError: // unused
194 case kActionCodeUmaReportedMax: // not an error code
195 case kActionCodeOmahaRequestHTTPResponseBase: // aggregated already
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800196 case kActionCodeDevModeFlag: // not an error code
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800197 case kActionCodeResumedFlag: // not an error code
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800198 case kActionCodeTestImageFlag: // not an error code
199 case kActionCodeTestOmahaUrlFlag: // not an error code
200 case kSpecialFlags: // not an error code
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800201 // These shouldn't happen. Enumerating these explicitly here so that we
202 // can let the compiler warn about new error codes that are added to
203 // action_processor.h but not added here.
204 LOG(WARNING) << "Unexpected error code for UpdateFailed";
205 break;
206
207 // Note: Not adding a default here so as to let the compiler warn us of
208 // any new enums that were added in the .h but not listed in this switch.
209 }
210}
211
Jay Srinivasan08262882012-12-28 19:29:43 -0800212bool PayloadState::ShouldBackoffDownload() {
213 if (response_.disable_payload_backoff) {
214 LOG(INFO) << "Payload backoff logic is disabled. "
215 "Can proceed with the download";
216 return false;
217 }
218
219 if (response_.is_delta_payload) {
220 // If delta payloads fail, we want to fallback quickly to full payloads as
221 // they are more likely to succeed. Exponential backoffs would greatly
222 // slow down the fallback to full payloads. So we don't backoff for delta
223 // payloads.
224 LOG(INFO) << "No backoffs for delta payloads. "
225 << "Can proceed with the download";
226 return false;
227 }
228
229 if (!utils::IsOfficialBuild()) {
230 // Backoffs are needed only for official builds. We do not want any delays
231 // or update failures due to backoffs during testing or development.
232 LOG(INFO) << "No backoffs for test/dev images. "
233 << "Can proceed with the download";
234 return false;
235 }
236
237 if (backoff_expiry_time_.is_null()) {
238 LOG(INFO) << "No backoff expiry time has been set. "
239 << "Can proceed with the download";
240 return false;
241 }
242
243 if (backoff_expiry_time_ < Time::Now()) {
244 LOG(INFO) << "The backoff expiry time ("
245 << utils::ToString(backoff_expiry_time_)
246 << ") has elapsed. Can proceed with the download";
247 return false;
248 }
249
250 LOG(INFO) << "Cannot proceed with downloads as we need to backoff until "
251 << utils::ToString(backoff_expiry_time_);
252 return true;
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800253}
254
255void PayloadState::IncrementPayloadAttemptNumber() {
Jay Srinivasan08262882012-12-28 19:29:43 -0800256 if (response_.is_delta_payload) {
257 LOG(INFO) << "Not incrementing payload attempt number for delta payloads";
258 return;
259 }
260
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800261 LOG(INFO) << "Incrementing the payload attempt number";
262 SetPayloadAttemptNumber(GetPayloadAttemptNumber() + 1);
Jay Srinivasan08262882012-12-28 19:29:43 -0800263 UpdateBackoffExpiryTime();
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800264}
265
266void PayloadState::IncrementUrlIndex() {
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800267 uint32_t next_url_index = GetUrlIndex() + 1;
Jay Srinivasan08262882012-12-28 19:29:43 -0800268 if (next_url_index < GetNumUrls()) {
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800269 LOG(INFO) << "Incrementing the URL index for next attempt";
270 SetUrlIndex(next_url_index);
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800271 } else {
272 LOG(INFO) << "Resetting the current URL index (" << GetUrlIndex() << ") to "
Jay Srinivasan08262882012-12-28 19:29:43 -0800273 << "0 as we only have " << GetNumUrls() << " URL(s)";
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800274 SetUrlIndex(0);
275 IncrementPayloadAttemptNumber();
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800276 }
Jay Srinivasan08262882012-12-28 19:29:43 -0800277
278 // Whenever we update the URL index, we should also clear the URL failure
279 // count so we can start over fresh for the new URL.
280 SetUrlFailureCount(0);
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800281}
282
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800283void PayloadState::IncrementFailureCount() {
284 uint32_t next_url_failure_count = GetUrlFailureCount() + 1;
Jay Srinivasan08262882012-12-28 19:29:43 -0800285 if (next_url_failure_count < response_.max_failure_count_per_url) {
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800286 LOG(INFO) << "Incrementing the URL failure count";
287 SetUrlFailureCount(next_url_failure_count);
288 } else {
289 LOG(INFO) << "Reached max number of failures for Url" << GetUrlIndex()
290 << ". Trying next available URL";
291 IncrementUrlIndex();
292 }
293}
294
Jay Srinivasan08262882012-12-28 19:29:43 -0800295void PayloadState::UpdateBackoffExpiryTime() {
296 if (response_.disable_payload_backoff) {
297 LOG(INFO) << "Resetting backoff expiry time as payload backoff is disabled";
298 SetBackoffExpiryTime(Time());
299 return;
300 }
301
302 if (GetPayloadAttemptNumber() == 0) {
303 SetBackoffExpiryTime(Time());
304 return;
305 }
306
307 // Since we're doing left-shift below, make sure we don't shift more
308 // than this. E.g. if uint32_t is 4-bytes, don't left-shift more than 30 bits,
309 // since we don't expect value of kMaxBackoffDays to be more than 100 anyway.
310 uint32_t num_days = 1; // the value to be shifted.
311 const uint32_t kMaxShifts = (sizeof(num_days) * 8) - 2;
312
313 // Normal backoff days is 2 raised to (payload_attempt_number - 1).
314 // E.g. if payload_attempt_number is over 30, limit power to 30.
315 uint32_t power = min(GetPayloadAttemptNumber() - 1, kMaxShifts);
316
317 // The number of days is the minimum of 2 raised to (payload_attempt_number
318 // - 1) or kMaxBackoffDays.
319 num_days = min(num_days << power, kMaxBackoffDays);
320
321 // We don't want all retries to happen exactly at the same time when
322 // retrying after backoff. So add some random minutes to fuzz.
323 int fuzz_minutes = utils::FuzzInt(0, kMaxBackoffFuzzMinutes);
324 TimeDelta next_backoff_interval = TimeDelta::FromDays(num_days) +
325 TimeDelta::FromMinutes(fuzz_minutes);
326 LOG(INFO) << "Incrementing the backoff expiry time by "
327 << utils::FormatTimeDelta(next_backoff_interval);
328 SetBackoffExpiryTime(Time::Now() + next_backoff_interval);
329}
330
331void PayloadState::ResetPersistedState() {
332 SetPayloadAttemptNumber(0);
333 SetUrlIndex(0);
334 SetUrlFailureCount(0);
335 UpdateBackoffExpiryTime(); // This will reset the backoff expiry time.
David Zeuthen9a017f22013-04-11 16:10:26 -0700336 SetUpdateTimestampStart(Time::Now());
337 SetUpdateTimestampEnd(Time()); // Set to null time
338 SetUpdateDurationUptime(TimeDelta::FromSeconds(0));
Jay Srinivasan08262882012-12-28 19:29:43 -0800339}
340
341string PayloadState::CalculateResponseSignature() {
342 string response_sign = StringPrintf("NumURLs = %d\n",
343 response_.payload_urls.size());
344
345 for (size_t i = 0; i < response_.payload_urls.size(); i++)
346 response_sign += StringPrintf("Url%d = %s\n",
347 i, response_.payload_urls[i].c_str());
348
349 response_sign += StringPrintf("Payload Size = %llu\n"
350 "Payload Sha256 Hash = %s\n"
351 "Metadata Size = %llu\n"
352 "Metadata Signature = %s\n"
353 "Is Delta Payload = %d\n"
354 "Max Failure Count Per Url = %d\n"
355 "Disable Payload Backoff = %d\n",
356 response_.size,
357 response_.hash.c_str(),
358 response_.metadata_size,
359 response_.metadata_signature.c_str(),
360 response_.is_delta_payload,
361 response_.max_failure_count_per_url,
362 response_.disable_payload_backoff);
363 return response_sign;
364}
365
366void PayloadState::LoadResponseSignature() {
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800367 CHECK(prefs_);
368 string stored_value;
Jay Srinivasan08262882012-12-28 19:29:43 -0800369 if (prefs_->Exists(kPrefsCurrentResponseSignature) &&
370 prefs_->GetString(kPrefsCurrentResponseSignature, &stored_value)) {
371 SetResponseSignature(stored_value);
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800372 }
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800373}
374
Jay Srinivasan08262882012-12-28 19:29:43 -0800375void PayloadState::SetResponseSignature(string response_signature) {
376 CHECK(prefs_);
377 response_signature_ = response_signature;
378 LOG(INFO) << "Current Response Signature = \n" << response_signature_;
379 prefs_->SetString(kPrefsCurrentResponseSignature, response_signature_);
380}
381
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800382void PayloadState::LoadPayloadAttemptNumber() {
383 CHECK(prefs_);
384 int64_t stored_value;
385 if (prefs_->Exists(kPrefsPayloadAttemptNumber) &&
386 prefs_->GetInt64(kPrefsPayloadAttemptNumber, &stored_value)) {
387 if (stored_value < 0) {
388 LOG(ERROR) << "Invalid payload attempt number (" << stored_value
389 << ") in persisted state. Defaulting to 0";
390 stored_value = 0;
391 }
Jay Srinivasan08262882012-12-28 19:29:43 -0800392 SetPayloadAttemptNumber(stored_value);
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800393 }
394}
395
396void PayloadState::SetPayloadAttemptNumber(uint32_t payload_attempt_number) {
397 CHECK(prefs_);
398 payload_attempt_number_ = payload_attempt_number;
399 LOG(INFO) << "Payload Attempt Number = " << payload_attempt_number_;
400 prefs_->SetInt64(kPrefsPayloadAttemptNumber, payload_attempt_number_);
401}
402
403void PayloadState::LoadUrlIndex() {
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800404 CHECK(prefs_);
405 int64_t stored_value;
406 if (prefs_->Exists(kPrefsCurrentUrlIndex) &&
407 prefs_->GetInt64(kPrefsCurrentUrlIndex, &stored_value)) {
Jay Srinivasan08262882012-12-28 19:29:43 -0800408 // We only check for basic sanity value here. Detailed check will be
409 // done in SetResponse once the first response comes in.
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800410 if (stored_value < 0) {
411 LOG(ERROR) << "Invalid URL Index (" << stored_value
412 << ") in persisted state. Defaulting to 0";
413 stored_value = 0;
414 }
Jay Srinivasan08262882012-12-28 19:29:43 -0800415 SetUrlIndex(stored_value);
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800416 }
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800417}
418
419void PayloadState::SetUrlIndex(uint32_t url_index) {
420 CHECK(prefs_);
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800421 url_index_ = url_index;
422 LOG(INFO) << "Current URL Index = " << url_index_;
423 prefs_->SetInt64(kPrefsCurrentUrlIndex, url_index_);
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800424}
425
426void PayloadState::LoadUrlFailureCount() {
427 CHECK(prefs_);
428 int64_t stored_value;
429 if (prefs_->Exists(kPrefsCurrentUrlFailureCount) &&
430 prefs_->GetInt64(kPrefsCurrentUrlFailureCount, &stored_value)) {
431 if (stored_value < 0) {
432 LOG(ERROR) << "Invalid URL Failure count (" << stored_value
433 << ") in persisted state. Defaulting to 0";
434 stored_value = 0;
435 }
Jay Srinivasan08262882012-12-28 19:29:43 -0800436 SetUrlFailureCount(stored_value);
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800437 }
438}
439
440void PayloadState::SetUrlFailureCount(uint32_t url_failure_count) {
441 CHECK(prefs_);
442 url_failure_count_ = url_failure_count;
443 LOG(INFO) << "Current URL (Url" << GetUrlIndex()
444 << ")'s Failure Count = " << url_failure_count_;
445 prefs_->SetInt64(kPrefsCurrentUrlFailureCount, url_failure_count_);
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800446}
447
Jay Srinivasan08262882012-12-28 19:29:43 -0800448void PayloadState::LoadBackoffExpiryTime() {
449 CHECK(prefs_);
450 int64_t stored_value;
451 if (!prefs_->Exists(kPrefsBackoffExpiryTime))
452 return;
453
454 if (!prefs_->GetInt64(kPrefsBackoffExpiryTime, &stored_value))
455 return;
456
457 Time stored_time = Time::FromInternalValue(stored_value);
458 if (stored_time > Time::Now() + TimeDelta::FromDays(kMaxBackoffDays)) {
459 LOG(ERROR) << "Invalid backoff expiry time ("
460 << utils::ToString(stored_time)
461 << ") in persisted state. Resetting.";
462 stored_time = Time();
463 }
464 SetBackoffExpiryTime(stored_time);
465}
466
467void PayloadState::SetBackoffExpiryTime(const Time& new_time) {
468 CHECK(prefs_);
469 backoff_expiry_time_ = new_time;
470 LOG(INFO) << "Backoff Expiry Time = "
471 << utils::ToString(backoff_expiry_time_);
472 prefs_->SetInt64(kPrefsBackoffExpiryTime,
473 backoff_expiry_time_.ToInternalValue());
474}
475
David Zeuthen9a017f22013-04-11 16:10:26 -0700476TimeDelta PayloadState::GetUpdateDuration() {
477 Time end_time = update_timestamp_end_.is_null() ? Time::Now() :
478 update_timestamp_end_;
479 return end_time - update_timestamp_start_;
480}
481
482void PayloadState::LoadUpdateTimestampStart() {
483 int64_t stored_value;
484 Time stored_time;
485
486 CHECK(prefs_);
487
488 Time now = Time::Now();
489
490 if (!prefs_->Exists(kPrefsUpdateTimestampStart)) {
491 // The preference missing is not unexpected - in that case, just
492 // use the current time as start time
493 stored_time = now;
494 } else if (!prefs_->GetInt64(kPrefsUpdateTimestampStart, &stored_value)) {
495 LOG(ERROR) << "Invalid UpdateTimestampStart value. Resetting.";
496 stored_time = now;
497 } else {
498 stored_time = Time::FromInternalValue(stored_value);
499 }
500
501 // Sanity check: If the time read from disk is in the future
502 // (modulo some slack to account for possible NTP drift
503 // adjustments), something is fishy and we should report and
504 // reset.
505 TimeDelta duration_according_to_stored_time = now - stored_time;
506 if (duration_according_to_stored_time < -kDurationSlack) {
507 LOG(ERROR) << "The UpdateTimestampStart value ("
508 << utils::ToString(stored_time)
509 << ") in persisted state is "
510 << duration_according_to_stored_time.InSeconds()
511 << " seconds in the future. Resetting.";
512 stored_time = now;
513 }
514
515 SetUpdateTimestampStart(stored_time);
516}
517
518void PayloadState::SetUpdateTimestampStart(const Time& value) {
519 CHECK(prefs_);
520 update_timestamp_start_ = value;
521 prefs_->SetInt64(kPrefsUpdateTimestampStart,
522 update_timestamp_start_.ToInternalValue());
523 LOG(INFO) << "Update Timestamp Start = "
524 << utils::ToString(update_timestamp_start_);
525}
526
527void PayloadState::SetUpdateTimestampEnd(const Time& value) {
528 update_timestamp_end_ = value;
529 LOG(INFO) << "Update Timestamp End = "
530 << utils::ToString(update_timestamp_end_);
531}
532
533TimeDelta PayloadState::GetUpdateDurationUptime() {
534 return update_duration_uptime_;
535}
536
537void PayloadState::LoadUpdateDurationUptime() {
538 int64_t stored_value;
539 TimeDelta stored_delta;
540
541 CHECK(prefs_);
542
543 if (!prefs_->Exists(kPrefsUpdateDurationUptime)) {
544 // The preference missing is not unexpected - in that case, just
545 // we'll use zero as the delta
546 } else if (!prefs_->GetInt64(kPrefsUpdateDurationUptime, &stored_value)) {
547 LOG(ERROR) << "Invalid UpdateDurationUptime value. Resetting.";
548 stored_delta = TimeDelta::FromSeconds(0);
549 } else {
550 stored_delta = TimeDelta::FromInternalValue(stored_value);
551 }
552
553 // Sanity-check: Uptime can never be greater than the wall-clock
554 // difference (modulo some slack). If it is, report and reset
555 // to the wall-clock difference.
556 TimeDelta diff = GetUpdateDuration() - stored_delta;
557 if (diff < -kDurationSlack) {
558 LOG(ERROR) << "The UpdateDurationUptime value ("
559 << stored_delta.InSeconds() << " seconds"
560 << ") in persisted state is "
561 << diff.InSeconds()
562 << " seconds larger than the wall-clock delta. Resetting.";
563 stored_delta = update_duration_current_;
564 }
565
566 SetUpdateDurationUptime(stored_delta);
567}
568
569void PayloadState::SetUpdateDurationUptimeExtended(const TimeDelta& value,
570 const Time& timestamp,
571 bool use_logging) {
572 CHECK(prefs_);
573 update_duration_uptime_ = value;
574 update_duration_uptime_timestamp_ = timestamp;
575 prefs_->SetInt64(kPrefsUpdateDurationUptime,
576 update_duration_uptime_.ToInternalValue());
577 if (use_logging) {
578 LOG(INFO) << "Update Duration Uptime = "
579 << update_duration_uptime_.InSeconds()
580 << " seconds";
581 }
582}
583
584void PayloadState::SetUpdateDurationUptime(const TimeDelta& value) {
585 SetUpdateDurationUptimeExtended(value, utils::GetMonotonicTime(), true);
586}
587
588void PayloadState::CalculateUpdateDurationUptime() {
589 Time now = utils::GetMonotonicTime();
590 TimeDelta uptime_since_last_update = now - update_duration_uptime_timestamp_;
591 TimeDelta new_uptime = update_duration_uptime_ + uptime_since_last_update;
592 // We're frequently called so avoid logging this write
593 SetUpdateDurationUptimeExtended(new_uptime, now, false);
594}
595
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800596} // namespace chromeos_update_engine