| Index: update_check_scheduler.cc | 
| diff --git a/update_check_scheduler.cc b/update_check_scheduler.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..c0a52ab8540257ec79916b0448a85c616930398e | 
| --- /dev/null | 
| +++ b/update_check_scheduler.cc | 
| @@ -0,0 +1,128 @@ | 
| +// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "update_engine/update_check_scheduler.h" | 
| + | 
| +#include "update_engine/utils.h" | 
| + | 
| +namespace chromeos_update_engine { | 
| + | 
| +const int UpdateCheckScheduler::kTimeoutOnce = 7 * 60;  // at 7 minutes | 
| +const int UpdateCheckScheduler::kTimeoutPeriodic = 45 * 60;  // every 45 minutes | 
| +const int UpdateCheckScheduler::kTimeoutRegularFuzz = 10 * 60;  // +/- 5 minutes | 
| +const int UpdateCheckScheduler::kTimeoutMaxBackoff = 4 * 60 * 60;  // 4 hours | 
| + | 
| +UpdateCheckScheduler::UpdateCheckScheduler(UpdateAttempter* update_attempter) | 
| +    : update_attempter_(update_attempter), | 
| +      enabled_(false), | 
| +      scheduled_(false), | 
| +      last_interval_(0) {} | 
| + | 
| +UpdateCheckScheduler::~UpdateCheckScheduler() {} | 
| + | 
| +void UpdateCheckScheduler::Run() { | 
| +  enabled_ = false; | 
| +  update_attempter_->set_update_check_scheduler(NULL); | 
| + | 
| +  if (!IsOfficialBuild()) { | 
| +    LOG(WARNING) << "Non-official build: periodic update checks disabled."; | 
| +    return; | 
| +  } | 
| +  if (IsBootDeviceRemovable()) { | 
| +    LOG(WARNING) << "Removable device boot: periodic update checks disabled."; | 
| +    return; | 
| +  } | 
| +  enabled_ = true; | 
| + | 
| +  // Registers this scheduler with the update attempter so that scheduler can be | 
| +  // notified of update status changes. | 
| +  update_attempter_->set_update_check_scheduler(this); | 
| + | 
| +  // Kicks off periodic update checks. The first check is scheduled | 
| +  // |kTimeoutOnce| seconds from now. Subsequent checks are scheduled by | 
| +  // ScheduleNextCheck, normally at |kTimeoutPeriodic|-second intervals. | 
| +  ScheduleCheck(kTimeoutOnce, kTimeoutRegularFuzz); | 
| +} | 
| + | 
| +bool UpdateCheckScheduler::IsBootDeviceRemovable() { | 
| +  return utils::IsRemovableDevice(utils::RootDevice(utils::BootDevice())); | 
| +} | 
| + | 
| +bool UpdateCheckScheduler::IsOfficialBuild() { | 
| +  return utils::IsOfficialBuild(); | 
| +} | 
| + | 
| +guint UpdateCheckScheduler::GTimeoutAddSeconds(guint interval, | 
| +                                               GSourceFunc function) { | 
| +  return g_timeout_add_seconds(interval, function, this); | 
| +} | 
| + | 
| +void UpdateCheckScheduler::ScheduleCheck(int interval, int fuzz) { | 
| +  if (!CanSchedule()) { | 
| +    return; | 
| +  } | 
| +  last_interval_ = interval; | 
| +  interval = utils::FuzzInt(interval, fuzz); | 
| +  if (interval < 0) { | 
| +    interval = 0; | 
| +  } | 
| +  GTimeoutAddSeconds(interval, StaticCheck); | 
| +  scheduled_ = true; | 
| +  LOG(INFO) << "Next update check in " << interval << " seconds."; | 
| +} | 
| + | 
| +gboolean UpdateCheckScheduler::StaticCheck(void* scheduler) { | 
| +  UpdateCheckScheduler* me = reinterpret_cast<UpdateCheckScheduler*>(scheduler); | 
| +  CHECK(me->scheduled_); | 
| +  me->scheduled_ = false; | 
| +  me->update_attempter_->Update("", ""); | 
| +  // This check ensures that future update checks will be or are already | 
| +  // scheduled. The check should never fail. A check failure means that there's | 
| +  // a bug that will most likely prevent further automatic update checks. It | 
| +  // seems better to crash in such cases and restart the update_engine daemon | 
| +  // into, hopefully, a known good state. | 
| +  CHECK(me->update_attempter_->status() != UPDATE_STATUS_IDLE || | 
| +        !me->CanSchedule()); | 
| +  return FALSE;  // Don't run again. | 
| +} | 
| + | 
| +void UpdateCheckScheduler::ComputeNextIntervalAndFuzz(int* next_interval, | 
| +                                                      int* next_fuzz) { | 
| +  int interval = 0; | 
| +  int fuzz = 0; | 
| +  // Implements exponential back off on 500 (Internal Server Error) and 503 | 
| +  // (Service Unavailable) HTTP response codes. | 
| +  if (update_attempter_->http_response_code() == 500 || | 
| +      update_attempter_->http_response_code() == 503) { | 
| +    interval = 2 * last_interval_; | 
| +    if (interval > kTimeoutMaxBackoff) { | 
| +      interval = kTimeoutMaxBackoff; | 
| +    } | 
| +    // Exponential back off is fuzzed by +/- |interval|/2. | 
| +    fuzz = interval; | 
| +  } | 
| +  // Ensures that under normal conditions the regular update check interval and | 
| +  // fuzz are used. Also covers the case where back off is required based on the | 
| +  // initial update check. | 
| +  if (interval < kTimeoutPeriodic) { | 
| +    interval = kTimeoutPeriodic; | 
| +    fuzz = kTimeoutRegularFuzz; | 
| +  } | 
| +  *next_interval = interval; | 
| +  *next_fuzz = fuzz; | 
| +} | 
| + | 
| +void UpdateCheckScheduler::ScheduleNextCheck() { | 
| +  int interval, fuzz; | 
| +  ComputeNextIntervalAndFuzz(&interval, &fuzz); | 
| +  ScheduleCheck(interval, fuzz); | 
| +} | 
| + | 
| +void UpdateCheckScheduler::SetUpdateStatus(UpdateStatus status) { | 
| +  if (status == UPDATE_STATUS_IDLE) { | 
| +    ScheduleNextCheck(); | 
| +  } | 
| +} | 
| + | 
| +}  // namespace chromeos_update_engine | 
|  |