blob: 4455e7fa16ea816ca91408130bf3658528ba342a [file] [log] [blame]
Gilad Arnoldae47a9a2014-03-26 12:16:47 -07001// Copyright (c) 2014 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/policy_manager/real_updater_provider.h"
6
7#include <inttypes.h>
8
9#include <string>
10
Gilad Arnoldae47a9a2014-03-26 12:16:47 -070011#include <base/strings/stringprintf.h>
Alex Deymoc7ab6162014-04-25 18:32:50 -070012#include <base/time/time.h>
Gilad Arnoldae47a9a2014-03-26 12:16:47 -070013#include <chromeos/dbus/service_constants.h>
14
15#include "update_engine/clock_interface.h"
16#include "update_engine/omaha_request_params.h"
17#include "update_engine/prefs.h"
18#include "update_engine/update_attempter.h"
19
20using base::StringPrintf;
21using base::Time;
22using base::TimeDelta;
23using chromeos_update_engine::OmahaRequestParams;
24using chromeos_update_engine::SystemState;
25using std::string;
26
27namespace chromeos_policy_manager {
28
29// A templated base class for all update related variables. Provides uniform
30// construction and a system state handle.
31template<typename T>
32class UpdaterVariableBase : public Variable<T> {
33 public:
34 UpdaterVariableBase(const string& name, SystemState* system_state)
35 : Variable<T>(name, kVariableModePoll), system_state_(system_state) {}
36
37 protected:
38 // The system state used for pulling information from the updater.
39 inline SystemState* system_state() const { return system_state_; }
40
41 private:
42 SystemState* const system_state_;
43};
44
45// Helper class for issuing a GetStatus() to the UpdateAttempter.
46class GetStatusHelper {
47 public:
48 GetStatusHelper(SystemState* system_state, string* errmsg) {
49 is_success_ = system_state->update_attempter()->GetStatus(
50 &last_checked_time_, &progress_, &update_status_, &new_version_,
51 &payload_size_);
52 if (!is_success_ && errmsg)
53 *errmsg = "Failed to get a status update from the update engine";
54 }
55
56 inline bool is_success() { return is_success_; }
57 inline int64_t last_checked_time() { return last_checked_time_; }
58 inline double progress() { return progress_; }
59 inline const string& update_status() { return update_status_; }
60 inline const string& new_version() { return new_version_; }
61 inline int64_t payload_size() { return payload_size_; }
62
63 private:
64 bool is_success_;
65 int64_t last_checked_time_;
66 double progress_;
67 string update_status_;
68 string new_version_;
69 int64_t payload_size_;
70};
71
72// A variable reporting the time when a last update check was issued.
73class LastCheckedTimeVariable : public UpdaterVariableBase<Time> {
74 public:
75 using UpdaterVariableBase<Time>::UpdaterVariableBase;
76
77 private:
78 virtual const Time* GetValue(TimeDelta /* timeout */,
79 string* errmsg) override {
80 GetStatusHelper raw(system_state(), errmsg);
81 if (!raw.is_success())
82 return NULL;
83
84 return new Time(Time::FromTimeT(raw.last_checked_time()));
85 }
86
87 DISALLOW_COPY_AND_ASSIGN(LastCheckedTimeVariable);
88};
89
90// A variable reporting the update (download) progress as a decimal fraction
91// between 0.0 and 1.0.
92class ProgressVariable : public UpdaterVariableBase<double> {
93 public:
94 using UpdaterVariableBase<double>::UpdaterVariableBase;
95
96 private:
97 virtual const double* GetValue(TimeDelta /* timeout */,
98 string* errmsg) override {
99 GetStatusHelper raw(system_state(), errmsg);
100 if (!raw.is_success())
101 return NULL;
102
103 if (raw.progress() < 0.0 || raw.progress() > 1.0) {
104 if (errmsg) {
105 *errmsg = StringPrintf("Invalid progress value received: %f",
106 raw.progress());
107 }
108 return NULL;
109 }
110
111 return new double(raw.progress());
112 }
113
114 DISALLOW_COPY_AND_ASSIGN(ProgressVariable);
115};
116
117// A variable reporting the stage in which the update process is.
118class StageVariable : public UpdaterVariableBase<Stage> {
119 public:
120 using UpdaterVariableBase<Stage>::UpdaterVariableBase;
121
122 private:
123 struct CurrOpStrToStage {
124 const char* str;
125 Stage stage;
126 };
127 static const CurrOpStrToStage curr_op_str_to_stage[];
128
129 // Note: the method is defined outside the class so arraysize can work.
130 virtual const Stage* GetValue(TimeDelta /* timeout */,
131 string* errmsg) override;
132
133 DISALLOW_COPY_AND_ASSIGN(StageVariable);
134};
135
136const StageVariable::CurrOpStrToStage StageVariable::curr_op_str_to_stage[] = {
137 {update_engine::kUpdateStatusIdle, Stage::kIdle},
138 {update_engine::kUpdateStatusCheckingForUpdate, Stage::kCheckingForUpdate},
139 {update_engine::kUpdateStatusUpdateAvailable, Stage::kUpdateAvailable},
140 {update_engine::kUpdateStatusDownloading, Stage::kDownloading},
141 {update_engine::kUpdateStatusVerifying, Stage::kVerifying},
142 {update_engine::kUpdateStatusFinalizing, Stage::kFinalizing},
143 {update_engine::kUpdateStatusUpdatedNeedReboot, Stage::kUpdatedNeedReboot},
144 {update_engine::kUpdateStatusReportingErrorEvent,
145 Stage::kReportingErrorEvent},
146 {update_engine::kUpdateStatusAttemptingRollback, Stage::kAttemptingRollback},
147};
148
149const Stage* StageVariable::GetValue(TimeDelta /* timeout */,
150 string* errmsg) {
151 GetStatusHelper raw(system_state(), errmsg);
152 if (!raw.is_success())
153 return NULL;
154
155 for (auto& key_val : curr_op_str_to_stage)
156 if (raw.update_status() == key_val.str)
157 return new Stage(key_val.stage);
158
159 if (errmsg)
160 *errmsg = string("Unknown update status: ") + raw.update_status();
161 return NULL;
162}
163
164// A variable reporting the version number that an update is updating to.
165class NewVersionVariable : public UpdaterVariableBase<string> {
166 public:
167 using UpdaterVariableBase<string>::UpdaterVariableBase;
168
169 private:
170 virtual const string* GetValue(TimeDelta /* timeout */,
171 string* errmsg) override {
172 GetStatusHelper raw(system_state(), errmsg);
173 if (!raw.is_success())
174 return NULL;
175
176 return new string(raw.new_version());
177 }
178
179 DISALLOW_COPY_AND_ASSIGN(NewVersionVariable);
180};
181
182// A variable reporting the size of the update being processed in bytes.
Alex Deymof967ebe2014-05-05 14:46:17 -0700183class PayloadSizeVariable : public UpdaterVariableBase<int64_t> {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700184 public:
Alex Deymof967ebe2014-05-05 14:46:17 -0700185 using UpdaterVariableBase<int64_t>::UpdaterVariableBase;
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700186
187 private:
Alex Deymof967ebe2014-05-05 14:46:17 -0700188 virtual const int64_t* GetValue(TimeDelta /* timeout */,
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700189 string* errmsg) override {
190 GetStatusHelper raw(system_state(), errmsg);
191 if (!raw.is_success())
192 return NULL;
193
194 if (raw.payload_size() < 0) {
195 if (errmsg)
196 *errmsg = string("Invalid payload size: %" PRId64, raw.payload_size());
197 return NULL;
198 }
199
Alex Deymof967ebe2014-05-05 14:46:17 -0700200 return new int64_t(raw.payload_size());
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700201 }
202
203 DISALLOW_COPY_AND_ASSIGN(PayloadSizeVariable);
204};
205
206// A variable reporting the point in time an update last completed in the
207// current boot cycle.
208//
209// TODO(garnold) In general, both the current boottime and wallclock time
210// readings should come from the time provider and be moderated by the
211// evaluation context, so that they are uniform throughout the evaluation of a
212// policy request.
213class UpdateCompletedTimeVariable : public UpdaterVariableBase<Time> {
214 public:
215 using UpdaterVariableBase<Time>::UpdaterVariableBase;
216
217 private:
218 virtual const Time* GetValue(TimeDelta /* timeout */,
219 string* errmsg) override {
220 Time update_boottime;
221 if (!system_state()->update_attempter()->GetBootTimeAtUpdate(
222 &update_boottime)) {
223 if (errmsg)
224 *errmsg = "Update completed time could not be read";
225 return NULL;
226 }
227
228 chromeos_update_engine::ClockInterface* clock = system_state()->clock();
229 Time curr_boottime = clock->GetBootTime();
230 if (curr_boottime < update_boottime) {
231 if (errmsg)
232 *errmsg = "Update completed time more recent than current time";
233 return NULL;
234 }
235 TimeDelta duration_since_update = curr_boottime - update_boottime;
236 return new Time(clock->GetWallclockTime() - duration_since_update);
237 }
238
239 DISALLOW_COPY_AND_ASSIGN(UpdateCompletedTimeVariable);
240};
241
242// Variables reporting the current image channel.
243class CurrChannelVariable : public UpdaterVariableBase<string> {
244 public:
245 using UpdaterVariableBase<string>::UpdaterVariableBase;
246
247 private:
248 virtual const string* GetValue(TimeDelta /* timeout */,
249 string* errmsg) override {
250 OmahaRequestParams* request_params = system_state()->request_params();
251 string channel = request_params->current_channel();
252 if (channel.empty()) {
253 if (errmsg)
254 *errmsg = "No current channel";
255 return NULL;
256 }
257 return new string(channel);
258 }
259
260 DISALLOW_COPY_AND_ASSIGN(CurrChannelVariable);
261};
262
263// Variables reporting the new image channel.
264class NewChannelVariable : public UpdaterVariableBase<string> {
265 public:
266 using UpdaterVariableBase<string>::UpdaterVariableBase;
267
268 private:
269 virtual const string* GetValue(TimeDelta /* timeout */,
270 string* errmsg) override {
271 OmahaRequestParams* request_params = system_state()->request_params();
272 string channel = request_params->target_channel();
273 if (channel.empty()) {
274 if (errmsg)
275 *errmsg = "No new channel";
276 return NULL;
277 }
278 return new string(channel);
279 }
280
281 DISALLOW_COPY_AND_ASSIGN(NewChannelVariable);
282};
283
284// A variable class for reading Boolean prefs values.
285class BooleanPrefVariable : public UpdaterVariableBase<bool> {
286 public:
287 BooleanPrefVariable(const string& name, SystemState* system_state,
288 const char* key, bool default_val)
289 : UpdaterVariableBase<bool>(name, system_state),
290 key_(key), default_val_(default_val) {}
291
292 private:
293 virtual const bool* GetValue(TimeDelta /* timeout */,
294 string* errmsg) override {
295 bool result = default_val_;
296 chromeos_update_engine::PrefsInterface* prefs = system_state()->prefs();
297 if (prefs && prefs->Exists(key_) && !prefs->GetBoolean(key_, &result)) {
298 if (errmsg)
299 *errmsg = string("Could not read boolean pref ") + key_;
300 return NULL;
301 }
302 return new bool(result);
303 }
304
305 // The Boolean preference key and default value.
306 const char* const key_;
307 const bool default_val_;
308
309 DISALLOW_COPY_AND_ASSIGN(BooleanPrefVariable);
310};
311
Gilad Arnolda6dab942014-04-25 11:46:03 -0700312// A variable returning the number of consecutive failed update checks.
313class ConsecutiveFailedUpdateChecksVariable :
314 public UpdaterVariableBase<unsigned int> {
315 public:
316 using UpdaterVariableBase<unsigned int>::UpdaterVariableBase;
317
318 private:
319 virtual const unsigned int* GetValue(TimeDelta /* timeout */,
320 string* /* errmsg */) override {
321 return new unsigned int(
322 system_state()->update_attempter()->consecutive_failed_update_checks());
323 }
324
325 DISALLOW_COPY_AND_ASSIGN(ConsecutiveFailedUpdateChecksVariable);
326};
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700327
328// RealUpdaterProvider methods.
329
330RealUpdaterProvider::RealUpdaterProvider(SystemState* system_state)
331 : system_state_(system_state),
Alex Deymoc7ab6162014-04-25 18:32:50 -0700332 var_updater_started_time_("updater_started_time",
333 system_state->clock()->GetWallclockTime()),
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700334 var_last_checked_time_(
335 new LastCheckedTimeVariable("last_checked_time", system_state_)),
336 var_update_completed_time_(
337 new UpdateCompletedTimeVariable("update_completed_time",
338 system_state_)),
339 var_progress_(new ProgressVariable("progress", system_state_)),
340 var_stage_(new StageVariable("stage", system_state_)),
341 var_new_version_(new NewVersionVariable("new_version", system_state_)),
342 var_payload_size_(new PayloadSizeVariable("payload_size", system_state_)),
343 var_curr_channel_(new CurrChannelVariable("curr_channel", system_state_)),
344 var_new_channel_(new NewChannelVariable("new_channel", system_state_)),
345 var_p2p_enabled_(
346 new BooleanPrefVariable("p2p_enabled", system_state_,
347 chromeos_update_engine::kPrefsP2PEnabled,
348 false)),
349 var_cellular_enabled_(
350 new BooleanPrefVariable(
351 "cellular_enabled", system_state_,
352 chromeos_update_engine::kPrefsUpdateOverCellularPermission,
Gilad Arnolda6dab942014-04-25 11:46:03 -0700353 false)),
354 var_consecutive_failed_update_checks_(
355 new ConsecutiveFailedUpdateChecksVariable(
356 "consecutive_failed_update_checks", system_state_)) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700357
358} // namespace chromeos_policy_manager