blob: 7dae71441f4261942b8296c894eed85c52e737c6 [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
Alex Deymo63784a52014-05-28 10:46:14 -07005#include "update_engine/update_manager/real_updater_provider.h"
Gilad Arnoldae47a9a2014-03-26 12:16:47 -07006
7#include <inttypes.h>
8
9#include <string>
10
Gilad Arnold44dc3bf2014-07-18 23:39:38 -070011#include <base/bind.h>
Gilad Arnoldae47a9a2014-03-26 12:16:47 -070012#include <base/strings/stringprintf.h>
Alex Deymoc7ab6162014-04-25 18:32:50 -070013#include <base/time/time.h>
Gilad Arnoldae47a9a2014-03-26 12:16:47 -070014#include <chromeos/dbus/service_constants.h>
15
16#include "update_engine/clock_interface.h"
17#include "update_engine/omaha_request_params.h"
18#include "update_engine/prefs.h"
19#include "update_engine/update_attempter.h"
20
21using base::StringPrintf;
22using base::Time;
23using base::TimeDelta;
24using chromeos_update_engine::OmahaRequestParams;
25using chromeos_update_engine::SystemState;
26using std::string;
27
Alex Deymo63784a52014-05-28 10:46:14 -070028namespace chromeos_update_manager {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -070029
30// A templated base class for all update related variables. Provides uniform
31// construction and a system state handle.
32template<typename T>
33class UpdaterVariableBase : public Variable<T> {
34 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -070035 UpdaterVariableBase(const string& name, VariableMode mode,
36 SystemState* system_state)
37 : Variable<T>(name, mode), system_state_(system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -070038
39 protected:
40 // The system state used for pulling information from the updater.
41 inline SystemState* system_state() const { return system_state_; }
42
43 private:
44 SystemState* const system_state_;
45};
46
47// Helper class for issuing a GetStatus() to the UpdateAttempter.
48class GetStatusHelper {
49 public:
50 GetStatusHelper(SystemState* system_state, string* errmsg) {
51 is_success_ = system_state->update_attempter()->GetStatus(
52 &last_checked_time_, &progress_, &update_status_, &new_version_,
53 &payload_size_);
54 if (!is_success_ && errmsg)
55 *errmsg = "Failed to get a status update from the update engine";
56 }
57
58 inline bool is_success() { return is_success_; }
59 inline int64_t last_checked_time() { return last_checked_time_; }
60 inline double progress() { return progress_; }
61 inline const string& update_status() { return update_status_; }
62 inline const string& new_version() { return new_version_; }
63 inline int64_t payload_size() { return payload_size_; }
64
65 private:
66 bool is_success_;
67 int64_t last_checked_time_;
68 double progress_;
69 string update_status_;
70 string new_version_;
71 int64_t payload_size_;
72};
73
74// A variable reporting the time when a last update check was issued.
75class LastCheckedTimeVariable : public UpdaterVariableBase<Time> {
76 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -070077 LastCheckedTimeVariable(const string& name, SystemState* system_state)
78 : UpdaterVariableBase<Time>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -070079
80 private:
81 virtual const Time* GetValue(TimeDelta /* timeout */,
82 string* errmsg) override {
83 GetStatusHelper raw(system_state(), errmsg);
84 if (!raw.is_success())
85 return NULL;
86
87 return new Time(Time::FromTimeT(raw.last_checked_time()));
88 }
89
90 DISALLOW_COPY_AND_ASSIGN(LastCheckedTimeVariable);
91};
92
93// A variable reporting the update (download) progress as a decimal fraction
94// between 0.0 and 1.0.
95class ProgressVariable : public UpdaterVariableBase<double> {
96 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -070097 ProgressVariable(const string& name, SystemState* system_state)
98 : UpdaterVariableBase<double>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -070099
100 private:
101 virtual const double* GetValue(TimeDelta /* timeout */,
102 string* errmsg) override {
103 GetStatusHelper raw(system_state(), errmsg);
104 if (!raw.is_success())
105 return NULL;
106
107 if (raw.progress() < 0.0 || raw.progress() > 1.0) {
108 if (errmsg) {
109 *errmsg = StringPrintf("Invalid progress value received: %f",
110 raw.progress());
111 }
112 return NULL;
113 }
114
115 return new double(raw.progress());
116 }
117
118 DISALLOW_COPY_AND_ASSIGN(ProgressVariable);
119};
120
121// A variable reporting the stage in which the update process is.
122class StageVariable : public UpdaterVariableBase<Stage> {
123 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700124 StageVariable(const string& name, SystemState* system_state)
125 : UpdaterVariableBase<Stage>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700126
127 private:
128 struct CurrOpStrToStage {
129 const char* str;
130 Stage stage;
131 };
132 static const CurrOpStrToStage curr_op_str_to_stage[];
133
134 // Note: the method is defined outside the class so arraysize can work.
135 virtual const Stage* GetValue(TimeDelta /* timeout */,
136 string* errmsg) override;
137
138 DISALLOW_COPY_AND_ASSIGN(StageVariable);
139};
140
141const StageVariable::CurrOpStrToStage StageVariable::curr_op_str_to_stage[] = {
142 {update_engine::kUpdateStatusIdle, Stage::kIdle},
143 {update_engine::kUpdateStatusCheckingForUpdate, Stage::kCheckingForUpdate},
144 {update_engine::kUpdateStatusUpdateAvailable, Stage::kUpdateAvailable},
145 {update_engine::kUpdateStatusDownloading, Stage::kDownloading},
146 {update_engine::kUpdateStatusVerifying, Stage::kVerifying},
147 {update_engine::kUpdateStatusFinalizing, Stage::kFinalizing},
148 {update_engine::kUpdateStatusUpdatedNeedReboot, Stage::kUpdatedNeedReboot},
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700149 { // NOLINT(whitespace/braces)
150 update_engine::kUpdateStatusReportingErrorEvent,
151 Stage::kReportingErrorEvent
152 },
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700153 {update_engine::kUpdateStatusAttemptingRollback, Stage::kAttemptingRollback},
154};
155
156const Stage* StageVariable::GetValue(TimeDelta /* timeout */,
157 string* errmsg) {
158 GetStatusHelper raw(system_state(), errmsg);
159 if (!raw.is_success())
160 return NULL;
161
162 for (auto& key_val : curr_op_str_to_stage)
163 if (raw.update_status() == key_val.str)
164 return new Stage(key_val.stage);
165
166 if (errmsg)
167 *errmsg = string("Unknown update status: ") + raw.update_status();
168 return NULL;
169}
170
171// A variable reporting the version number that an update is updating to.
172class NewVersionVariable : public UpdaterVariableBase<string> {
173 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700174 NewVersionVariable(const string& name, SystemState* system_state)
175 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700176
177 private:
178 virtual const string* GetValue(TimeDelta /* timeout */,
179 string* errmsg) override {
180 GetStatusHelper raw(system_state(), errmsg);
181 if (!raw.is_success())
182 return NULL;
183
184 return new string(raw.new_version());
185 }
186
187 DISALLOW_COPY_AND_ASSIGN(NewVersionVariable);
188};
189
190// A variable reporting the size of the update being processed in bytes.
Alex Deymof967ebe2014-05-05 14:46:17 -0700191class PayloadSizeVariable : public UpdaterVariableBase<int64_t> {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700192 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700193 PayloadSizeVariable(const string& name, SystemState* system_state)
194 : UpdaterVariableBase<int64_t>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700195
196 private:
Alex Deymof967ebe2014-05-05 14:46:17 -0700197 virtual const int64_t* GetValue(TimeDelta /* timeout */,
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700198 string* errmsg) override {
199 GetStatusHelper raw(system_state(), errmsg);
200 if (!raw.is_success())
201 return NULL;
202
203 if (raw.payload_size() < 0) {
204 if (errmsg)
205 *errmsg = string("Invalid payload size: %" PRId64, raw.payload_size());
206 return NULL;
207 }
208
Alex Deymof967ebe2014-05-05 14:46:17 -0700209 return new int64_t(raw.payload_size());
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700210 }
211
212 DISALLOW_COPY_AND_ASSIGN(PayloadSizeVariable);
213};
214
215// A variable reporting the point in time an update last completed in the
216// current boot cycle.
217//
218// TODO(garnold) In general, both the current boottime and wallclock time
219// readings should come from the time provider and be moderated by the
220// evaluation context, so that they are uniform throughout the evaluation of a
221// policy request.
222class UpdateCompletedTimeVariable : public UpdaterVariableBase<Time> {
223 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700224 UpdateCompletedTimeVariable(const string& name, SystemState* system_state)
225 : UpdaterVariableBase<Time>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700226
227 private:
228 virtual const Time* GetValue(TimeDelta /* timeout */,
229 string* errmsg) override {
230 Time update_boottime;
231 if (!system_state()->update_attempter()->GetBootTimeAtUpdate(
232 &update_boottime)) {
233 if (errmsg)
234 *errmsg = "Update completed time could not be read";
235 return NULL;
236 }
237
238 chromeos_update_engine::ClockInterface* clock = system_state()->clock();
239 Time curr_boottime = clock->GetBootTime();
240 if (curr_boottime < update_boottime) {
241 if (errmsg)
242 *errmsg = "Update completed time more recent than current time";
243 return NULL;
244 }
245 TimeDelta duration_since_update = curr_boottime - update_boottime;
246 return new Time(clock->GetWallclockTime() - duration_since_update);
247 }
248
249 DISALLOW_COPY_AND_ASSIGN(UpdateCompletedTimeVariable);
250};
251
252// Variables reporting the current image channel.
253class CurrChannelVariable : public UpdaterVariableBase<string> {
254 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700255 CurrChannelVariable(const string& name, SystemState* system_state)
256 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700257
258 private:
259 virtual const string* GetValue(TimeDelta /* timeout */,
260 string* errmsg) override {
261 OmahaRequestParams* request_params = system_state()->request_params();
262 string channel = request_params->current_channel();
263 if (channel.empty()) {
264 if (errmsg)
265 *errmsg = "No current channel";
266 return NULL;
267 }
268 return new string(channel);
269 }
270
271 DISALLOW_COPY_AND_ASSIGN(CurrChannelVariable);
272};
273
274// Variables reporting the new image channel.
275class NewChannelVariable : public UpdaterVariableBase<string> {
276 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700277 NewChannelVariable(const string& name, SystemState* system_state)
278 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700279
280 private:
281 virtual const string* GetValue(TimeDelta /* timeout */,
282 string* errmsg) override {
283 OmahaRequestParams* request_params = system_state()->request_params();
284 string channel = request_params->target_channel();
285 if (channel.empty()) {
286 if (errmsg)
287 *errmsg = "No new channel";
288 return NULL;
289 }
290 return new string(channel);
291 }
292
293 DISALLOW_COPY_AND_ASSIGN(NewChannelVariable);
294};
295
296// A variable class for reading Boolean prefs values.
297class BooleanPrefVariable : public UpdaterVariableBase<bool> {
298 public:
299 BooleanPrefVariable(const string& name, SystemState* system_state,
300 const char* key, bool default_val)
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700301 : UpdaterVariableBase<bool>(name, kVariableModePoll, system_state),
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700302 key_(key), default_val_(default_val) {}
303
304 private:
305 virtual const bool* GetValue(TimeDelta /* timeout */,
306 string* errmsg) override {
307 bool result = default_val_;
308 chromeos_update_engine::PrefsInterface* prefs = system_state()->prefs();
309 if (prefs && prefs->Exists(key_) && !prefs->GetBoolean(key_, &result)) {
310 if (errmsg)
311 *errmsg = string("Could not read boolean pref ") + key_;
312 return NULL;
313 }
314 return new bool(result);
315 }
316
317 // The Boolean preference key and default value.
318 const char* const key_;
319 const bool default_val_;
320
321 DISALLOW_COPY_AND_ASSIGN(BooleanPrefVariable);
322};
323
Gilad Arnolda6dab942014-04-25 11:46:03 -0700324// A variable returning the number of consecutive failed update checks.
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700325class ConsecutiveFailedUpdateChecksVariable
326 : public UpdaterVariableBase<unsigned int> {
Gilad Arnolda6dab942014-04-25 11:46:03 -0700327 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700328 ConsecutiveFailedUpdateChecksVariable(const string& name,
329 SystemState* system_state)
330 : UpdaterVariableBase<unsigned int>(name, kVariableModePoll,
331 system_state) {}
Gilad Arnolda6dab942014-04-25 11:46:03 -0700332
333 private:
334 virtual const unsigned int* GetValue(TimeDelta /* timeout */,
335 string* /* errmsg */) override {
336 return new unsigned int(
337 system_state()->update_attempter()->consecutive_failed_update_checks());
338 }
339
340 DISALLOW_COPY_AND_ASSIGN(ConsecutiveFailedUpdateChecksVariable);
341};
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700342
Gilad Arnolda0258a52014-07-10 16:21:19 -0700343// A variable returning the server-dictated poll interval.
344class ServerDictatedPollIntervalVariable
345 : public UpdaterVariableBase<unsigned int> {
346 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700347 ServerDictatedPollIntervalVariable(const string& name,
348 SystemState* system_state)
349 : UpdaterVariableBase<unsigned int>(name, kVariableModePoll,
350 system_state) {}
Gilad Arnolda0258a52014-07-10 16:21:19 -0700351
352 private:
353 virtual const unsigned int* GetValue(TimeDelta /* timeout */,
354 string* /* errmsg */) override {
355 return new unsigned int(
356 system_state()->update_attempter()->server_dictated_poll_interval());
357 }
358
359 DISALLOW_COPY_AND_ASSIGN(ServerDictatedPollIntervalVariable);
360};
361
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700362// An async variable that tracks changes to interactive update requests.
363class InteractiveUpdateRequestedVariable : public UpdaterVariableBase<bool> {
364 public:
365 InteractiveUpdateRequestedVariable(const string& name,
366 SystemState* system_state)
367 : UpdaterVariableBase<bool>::UpdaterVariableBase(name, kVariableModeAsync,
368 system_state) {
369 system_state->update_attempter()->set_interactive_update_pending_callback(
370 new base::Callback<void(bool)>( // NOLINT(readability/function)
371 base::Bind(&InteractiveUpdateRequestedVariable::Reset,
372 base::Unretained(this))));
373 }
374
375 private:
376 virtual const bool* GetValue(TimeDelta /* timeout */,
377 string* /* errmsg */) override {
378 return new bool(interactive_update_requested_);
379 }
380
381 void Reset(bool value) {
382 if (interactive_update_requested_ != value) {
383 interactive_update_requested_ = value;
384 NotifyValueChanged();
385 }
386 }
387
388 bool interactive_update_requested_ = false;
389
390 DISALLOW_COPY_AND_ASSIGN(InteractiveUpdateRequestedVariable);
391};
392
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700393// RealUpdaterProvider methods.
394
395RealUpdaterProvider::RealUpdaterProvider(SystemState* system_state)
396 : system_state_(system_state),
Alex Deymoc7ab6162014-04-25 18:32:50 -0700397 var_updater_started_time_("updater_started_time",
398 system_state->clock()->GetWallclockTime()),
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700399 var_last_checked_time_(
400 new LastCheckedTimeVariable("last_checked_time", system_state_)),
401 var_update_completed_time_(
402 new UpdateCompletedTimeVariable("update_completed_time",
403 system_state_)),
404 var_progress_(new ProgressVariable("progress", system_state_)),
405 var_stage_(new StageVariable("stage", system_state_)),
406 var_new_version_(new NewVersionVariable("new_version", system_state_)),
407 var_payload_size_(new PayloadSizeVariable("payload_size", system_state_)),
408 var_curr_channel_(new CurrChannelVariable("curr_channel", system_state_)),
409 var_new_channel_(new NewChannelVariable("new_channel", system_state_)),
410 var_p2p_enabled_(
411 new BooleanPrefVariable("p2p_enabled", system_state_,
412 chromeos_update_engine::kPrefsP2PEnabled,
413 false)),
414 var_cellular_enabled_(
415 new BooleanPrefVariable(
416 "cellular_enabled", system_state_,
417 chromeos_update_engine::kPrefsUpdateOverCellularPermission,
Gilad Arnolda6dab942014-04-25 11:46:03 -0700418 false)),
419 var_consecutive_failed_update_checks_(
420 new ConsecutiveFailedUpdateChecksVariable(
Gilad Arnolda0258a52014-07-10 16:21:19 -0700421 "consecutive_failed_update_checks", system_state_)),
422 var_server_dictated_poll_interval_(
423 new ServerDictatedPollIntervalVariable(
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700424 "server_dictated_poll_interval", system_state_)),
425 var_interactive_update_requested_(
426 new InteractiveUpdateRequestedVariable(
427 "interactive_update_requested", system_state_)) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700428
Alex Deymo63784a52014-05-28 10:46:14 -0700429} // namespace chromeos_update_manager