blob: 3d00ff38ab13a28319687c90a146e8ae2a59dae5 [file] [log] [blame]
Darin Petkov1023a602010-08-30 13:47:51 -07001// Copyright (c) 2010 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/update_check_scheduler.h"
6
7#include "update_engine/utils.h"
8
9namespace chromeos_update_engine {
10
11const int UpdateCheckScheduler::kTimeoutOnce = 7 * 60; // at 7 minutes
12const int UpdateCheckScheduler::kTimeoutPeriodic = 45 * 60; // every 45 minutes
13const int UpdateCheckScheduler::kTimeoutRegularFuzz = 10 * 60; // +/- 5 minutes
14const int UpdateCheckScheduler::kTimeoutMaxBackoff = 4 * 60 * 60; // 4 hours
15
16UpdateCheckScheduler::UpdateCheckScheduler(UpdateAttempter* update_attempter)
17 : update_attempter_(update_attempter),
18 enabled_(false),
19 scheduled_(false),
Darin Petkov85ced132010-09-01 10:20:56 -070020 last_interval_(0),
21 poll_interval_(0) {}
Darin Petkov1023a602010-08-30 13:47:51 -070022
23UpdateCheckScheduler::~UpdateCheckScheduler() {}
24
25void UpdateCheckScheduler::Run() {
26 enabled_ = false;
27 update_attempter_->set_update_check_scheduler(NULL);
28
29 if (!IsOfficialBuild()) {
30 LOG(WARNING) << "Non-official build: periodic update checks disabled.";
31 return;
32 }
33 if (IsBootDeviceRemovable()) {
34 LOG(WARNING) << "Removable device boot: periodic update checks disabled.";
35 return;
36 }
37 enabled_ = true;
38
39 // Registers this scheduler with the update attempter so that scheduler can be
40 // notified of update status changes.
41 update_attempter_->set_update_check_scheduler(this);
42
43 // Kicks off periodic update checks. The first check is scheduled
44 // |kTimeoutOnce| seconds from now. Subsequent checks are scheduled by
45 // ScheduleNextCheck, normally at |kTimeoutPeriodic|-second intervals.
46 ScheduleCheck(kTimeoutOnce, kTimeoutRegularFuzz);
47}
48
49bool UpdateCheckScheduler::IsBootDeviceRemovable() {
50 return utils::IsRemovableDevice(utils::RootDevice(utils::BootDevice()));
51}
52
53bool UpdateCheckScheduler::IsOfficialBuild() {
54 return utils::IsOfficialBuild();
55}
56
57guint UpdateCheckScheduler::GTimeoutAddSeconds(guint interval,
58 GSourceFunc function) {
59 return g_timeout_add_seconds(interval, function, this);
60}
61
62void UpdateCheckScheduler::ScheduleCheck(int interval, int fuzz) {
63 if (!CanSchedule()) {
64 return;
65 }
66 last_interval_ = interval;
67 interval = utils::FuzzInt(interval, fuzz);
68 if (interval < 0) {
69 interval = 0;
70 }
71 GTimeoutAddSeconds(interval, StaticCheck);
72 scheduled_ = true;
73 LOG(INFO) << "Next update check in " << interval << " seconds.";
74}
75
76gboolean UpdateCheckScheduler::StaticCheck(void* scheduler) {
77 UpdateCheckScheduler* me = reinterpret_cast<UpdateCheckScheduler*>(scheduler);
78 CHECK(me->scheduled_);
79 me->scheduled_ = false;
80 me->update_attempter_->Update("", "");
81 // This check ensures that future update checks will be or are already
82 // scheduled. The check should never fail. A check failure means that there's
83 // a bug that will most likely prevent further automatic update checks. It
84 // seems better to crash in such cases and restart the update_engine daemon
85 // into, hopefully, a known good state.
86 CHECK(me->update_attempter_->status() != UPDATE_STATUS_IDLE ||
87 !me->CanSchedule());
88 return FALSE; // Don't run again.
89}
90
91void UpdateCheckScheduler::ComputeNextIntervalAndFuzz(int* next_interval,
92 int* next_fuzz) {
93 int interval = 0;
Darin Petkov85ced132010-09-01 10:20:56 -070094 if (poll_interval_ > 0) {
95 // Server-dictated poll interval.
96 interval = poll_interval_;
97 LOG(WARNING) << "Using server-dictated poll interval: " << interval;
98 } else if (update_attempter_->http_response_code() == 500 ||
99 update_attempter_->http_response_code() == 503) {
100 // Implements exponential back off on 500 (Internal Server Error) and 503
101 // (Service Unavailable) HTTP response codes.
Darin Petkov1023a602010-08-30 13:47:51 -0700102 interval = 2 * last_interval_;
Darin Petkov85ced132010-09-01 10:20:56 -0700103 LOG(WARNING) << "Exponential back off due to 500/503 HTTP response code.";
Darin Petkov1023a602010-08-30 13:47:51 -0700104 }
Darin Petkov85ced132010-09-01 10:20:56 -0700105 if (interval > kTimeoutMaxBackoff) {
106 interval = kTimeoutMaxBackoff;
107 }
108 // Back off and server-dictated poll intervals are fuzzed by +/- |interval|/2.
109 int fuzz = interval;
110
Darin Petkov1023a602010-08-30 13:47:51 -0700111 // Ensures that under normal conditions the regular update check interval and
112 // fuzz are used. Also covers the case where back off is required based on the
113 // initial update check.
114 if (interval < kTimeoutPeriodic) {
115 interval = kTimeoutPeriodic;
116 fuzz = kTimeoutRegularFuzz;
117 }
118 *next_interval = interval;
119 *next_fuzz = fuzz;
120}
121
122void UpdateCheckScheduler::ScheduleNextCheck() {
123 int interval, fuzz;
124 ComputeNextIntervalAndFuzz(&interval, &fuzz);
125 ScheduleCheck(interval, fuzz);
126}
127
128void UpdateCheckScheduler::SetUpdateStatus(UpdateStatus status) {
129 if (status == UPDATE_STATUS_IDLE) {
130 ScheduleNextCheck();
131 }
132}
133
134} // namespace chromeos_update_engine