blob: c525b8f056bfc0f257034b8b33aa4657887a7af0 [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:
Alex Vakulenko157fe302014-08-11 15:59:58 -070081 const Time* GetValue(TimeDelta /* timeout */, string* errmsg) override {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -070082 GetStatusHelper raw(system_state(), errmsg);
83 if (!raw.is_success())
84 return NULL;
85
86 return new Time(Time::FromTimeT(raw.last_checked_time()));
87 }
88
89 DISALLOW_COPY_AND_ASSIGN(LastCheckedTimeVariable);
90};
91
92// A variable reporting the update (download) progress as a decimal fraction
93// between 0.0 and 1.0.
94class ProgressVariable : public UpdaterVariableBase<double> {
95 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -070096 ProgressVariable(const string& name, SystemState* system_state)
97 : UpdaterVariableBase<double>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -070098
99 private:
Alex Vakulenko157fe302014-08-11 15:59:58 -0700100 const double* GetValue(TimeDelta /* timeout */, string* errmsg) override {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700101 GetStatusHelper raw(system_state(), errmsg);
102 if (!raw.is_success())
103 return NULL;
104
105 if (raw.progress() < 0.0 || raw.progress() > 1.0) {
106 if (errmsg) {
107 *errmsg = StringPrintf("Invalid progress value received: %f",
108 raw.progress());
109 }
110 return NULL;
111 }
112
113 return new double(raw.progress());
114 }
115
116 DISALLOW_COPY_AND_ASSIGN(ProgressVariable);
117};
118
119// A variable reporting the stage in which the update process is.
120class StageVariable : public UpdaterVariableBase<Stage> {
121 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700122 StageVariable(const string& name, SystemState* system_state)
123 : UpdaterVariableBase<Stage>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700124
125 private:
126 struct CurrOpStrToStage {
127 const char* str;
128 Stage stage;
129 };
130 static const CurrOpStrToStage curr_op_str_to_stage[];
131
132 // Note: the method is defined outside the class so arraysize can work.
Alex Vakulenko157fe302014-08-11 15:59:58 -0700133 const Stage* GetValue(TimeDelta /* timeout */, string* errmsg) override;
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700134
135 DISALLOW_COPY_AND_ASSIGN(StageVariable);
136};
137
138const StageVariable::CurrOpStrToStage StageVariable::curr_op_str_to_stage[] = {
139 {update_engine::kUpdateStatusIdle, Stage::kIdle},
140 {update_engine::kUpdateStatusCheckingForUpdate, Stage::kCheckingForUpdate},
141 {update_engine::kUpdateStatusUpdateAvailable, Stage::kUpdateAvailable},
142 {update_engine::kUpdateStatusDownloading, Stage::kDownloading},
143 {update_engine::kUpdateStatusVerifying, Stage::kVerifying},
144 {update_engine::kUpdateStatusFinalizing, Stage::kFinalizing},
145 {update_engine::kUpdateStatusUpdatedNeedReboot, Stage::kUpdatedNeedReboot},
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700146 { // NOLINT(whitespace/braces)
147 update_engine::kUpdateStatusReportingErrorEvent,
148 Stage::kReportingErrorEvent
149 },
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700150 {update_engine::kUpdateStatusAttemptingRollback, Stage::kAttemptingRollback},
151};
152
153const Stage* StageVariable::GetValue(TimeDelta /* timeout */,
154 string* errmsg) {
155 GetStatusHelper raw(system_state(), errmsg);
156 if (!raw.is_success())
157 return NULL;
158
159 for (auto& key_val : curr_op_str_to_stage)
160 if (raw.update_status() == key_val.str)
161 return new Stage(key_val.stage);
162
163 if (errmsg)
164 *errmsg = string("Unknown update status: ") + raw.update_status();
165 return NULL;
166}
167
168// A variable reporting the version number that an update is updating to.
169class NewVersionVariable : public UpdaterVariableBase<string> {
170 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700171 NewVersionVariable(const string& name, SystemState* system_state)
172 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700173
174 private:
Alex Vakulenko157fe302014-08-11 15:59:58 -0700175 const string* GetValue(TimeDelta /* timeout */, string* errmsg) override {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700176 GetStatusHelper raw(system_state(), errmsg);
177 if (!raw.is_success())
178 return NULL;
179
180 return new string(raw.new_version());
181 }
182
183 DISALLOW_COPY_AND_ASSIGN(NewVersionVariable);
184};
185
186// A variable reporting the size of the update being processed in bytes.
Alex Deymof967ebe2014-05-05 14:46:17 -0700187class PayloadSizeVariable : public UpdaterVariableBase<int64_t> {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700188 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700189 PayloadSizeVariable(const string& name, SystemState* system_state)
190 : UpdaterVariableBase<int64_t>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700191
192 private:
Alex Vakulenko157fe302014-08-11 15:59:58 -0700193 const int64_t* GetValue(TimeDelta /* timeout */, string* errmsg) override {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700194 GetStatusHelper raw(system_state(), errmsg);
195 if (!raw.is_success())
196 return NULL;
197
198 if (raw.payload_size() < 0) {
199 if (errmsg)
200 *errmsg = string("Invalid payload size: %" PRId64, raw.payload_size());
201 return NULL;
202 }
203
Alex Deymof967ebe2014-05-05 14:46:17 -0700204 return new int64_t(raw.payload_size());
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700205 }
206
207 DISALLOW_COPY_AND_ASSIGN(PayloadSizeVariable);
208};
209
210// A variable reporting the point in time an update last completed in the
211// current boot cycle.
212//
213// TODO(garnold) In general, both the current boottime and wallclock time
214// readings should come from the time provider and be moderated by the
215// evaluation context, so that they are uniform throughout the evaluation of a
216// policy request.
217class UpdateCompletedTimeVariable : public UpdaterVariableBase<Time> {
218 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700219 UpdateCompletedTimeVariable(const string& name, SystemState* system_state)
220 : UpdaterVariableBase<Time>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700221
222 private:
Alex Vakulenko157fe302014-08-11 15:59:58 -0700223 const Time* GetValue(TimeDelta /* timeout */, string* errmsg) override {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700224 Time update_boottime;
225 if (!system_state()->update_attempter()->GetBootTimeAtUpdate(
226 &update_boottime)) {
227 if (errmsg)
228 *errmsg = "Update completed time could not be read";
229 return NULL;
230 }
231
232 chromeos_update_engine::ClockInterface* clock = system_state()->clock();
233 Time curr_boottime = clock->GetBootTime();
234 if (curr_boottime < update_boottime) {
235 if (errmsg)
236 *errmsg = "Update completed time more recent than current time";
237 return NULL;
238 }
239 TimeDelta duration_since_update = curr_boottime - update_boottime;
240 return new Time(clock->GetWallclockTime() - duration_since_update);
241 }
242
243 DISALLOW_COPY_AND_ASSIGN(UpdateCompletedTimeVariable);
244};
245
246// Variables reporting the current image channel.
247class CurrChannelVariable : public UpdaterVariableBase<string> {
248 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700249 CurrChannelVariable(const string& name, SystemState* system_state)
250 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700251
252 private:
Alex Vakulenko157fe302014-08-11 15:59:58 -0700253 const string* GetValue(TimeDelta /* timeout */, string* errmsg) override {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700254 OmahaRequestParams* request_params = system_state()->request_params();
255 string channel = request_params->current_channel();
256 if (channel.empty()) {
257 if (errmsg)
258 *errmsg = "No current channel";
259 return NULL;
260 }
261 return new string(channel);
262 }
263
264 DISALLOW_COPY_AND_ASSIGN(CurrChannelVariable);
265};
266
267// Variables reporting the new image channel.
268class NewChannelVariable : public UpdaterVariableBase<string> {
269 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700270 NewChannelVariable(const string& name, SystemState* system_state)
271 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700272
273 private:
Alex Vakulenko157fe302014-08-11 15:59:58 -0700274 const string* GetValue(TimeDelta /* timeout */, string* errmsg) override {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700275 OmahaRequestParams* request_params = system_state()->request_params();
276 string channel = request_params->target_channel();
277 if (channel.empty()) {
278 if (errmsg)
279 *errmsg = "No new channel";
280 return NULL;
281 }
282 return new string(channel);
283 }
284
285 DISALLOW_COPY_AND_ASSIGN(NewChannelVariable);
286};
287
288// A variable class for reading Boolean prefs values.
289class BooleanPrefVariable : public UpdaterVariableBase<bool> {
290 public:
291 BooleanPrefVariable(const string& name, SystemState* system_state,
292 const char* key, bool default_val)
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700293 : UpdaterVariableBase<bool>(name, kVariableModePoll, system_state),
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700294 key_(key), default_val_(default_val) {}
295
296 private:
Alex Vakulenko157fe302014-08-11 15:59:58 -0700297 const bool* GetValue(TimeDelta /* timeout */, string* errmsg) override {
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700298 bool result = default_val_;
299 chromeos_update_engine::PrefsInterface* prefs = system_state()->prefs();
300 if (prefs && prefs->Exists(key_) && !prefs->GetBoolean(key_, &result)) {
301 if (errmsg)
302 *errmsg = string("Could not read boolean pref ") + key_;
303 return NULL;
304 }
305 return new bool(result);
306 }
307
308 // The Boolean preference key and default value.
309 const char* const key_;
310 const bool default_val_;
311
312 DISALLOW_COPY_AND_ASSIGN(BooleanPrefVariable);
313};
314
Gilad Arnolda6dab942014-04-25 11:46:03 -0700315// A variable returning the number of consecutive failed update checks.
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700316class ConsecutiveFailedUpdateChecksVariable
317 : public UpdaterVariableBase<unsigned int> {
Gilad Arnolda6dab942014-04-25 11:46:03 -0700318 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700319 ConsecutiveFailedUpdateChecksVariable(const string& name,
320 SystemState* system_state)
321 : UpdaterVariableBase<unsigned int>(name, kVariableModePoll,
322 system_state) {}
Gilad Arnolda6dab942014-04-25 11:46:03 -0700323
324 private:
Alex Vakulenko157fe302014-08-11 15:59:58 -0700325 const unsigned int* GetValue(TimeDelta /* timeout */,
326 string* /* errmsg */) override {
Gilad Arnolda6dab942014-04-25 11:46:03 -0700327 return new unsigned int(
328 system_state()->update_attempter()->consecutive_failed_update_checks());
329 }
330
331 DISALLOW_COPY_AND_ASSIGN(ConsecutiveFailedUpdateChecksVariable);
332};
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700333
Gilad Arnolda0258a52014-07-10 16:21:19 -0700334// A variable returning the server-dictated poll interval.
335class ServerDictatedPollIntervalVariable
336 : public UpdaterVariableBase<unsigned int> {
337 public:
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700338 ServerDictatedPollIntervalVariable(const string& name,
339 SystemState* system_state)
340 : UpdaterVariableBase<unsigned int>(name, kVariableModePoll,
341 system_state) {}
Gilad Arnolda0258a52014-07-10 16:21:19 -0700342
343 private:
Alex Vakulenko157fe302014-08-11 15:59:58 -0700344 const unsigned int* GetValue(TimeDelta /* timeout */,
345 string* /* errmsg */) override {
Gilad Arnolda0258a52014-07-10 16:21:19 -0700346 return new unsigned int(
347 system_state()->update_attempter()->server_dictated_poll_interval());
348 }
349
350 DISALLOW_COPY_AND_ASSIGN(ServerDictatedPollIntervalVariable);
351};
352
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700353// An async variable that tracks changes to interactive update requests.
354class InteractiveUpdateRequestedVariable : public UpdaterVariableBase<bool> {
355 public:
356 InteractiveUpdateRequestedVariable(const string& name,
357 SystemState* system_state)
358 : UpdaterVariableBase<bool>::UpdaterVariableBase(name, kVariableModeAsync,
359 system_state) {
360 system_state->update_attempter()->set_interactive_update_pending_callback(
361 new base::Callback<void(bool)>( // NOLINT(readability/function)
362 base::Bind(&InteractiveUpdateRequestedVariable::Reset,
363 base::Unretained(this))));
364 }
365
366 private:
Alex Vakulenko157fe302014-08-11 15:59:58 -0700367 const bool* GetValue(TimeDelta /* timeout */,
368 string* /* errmsg */) override {
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700369 return new bool(interactive_update_requested_);
370 }
371
372 void Reset(bool value) {
373 if (interactive_update_requested_ != value) {
374 interactive_update_requested_ = value;
375 NotifyValueChanged();
376 }
377 }
378
379 bool interactive_update_requested_ = false;
380
381 DISALLOW_COPY_AND_ASSIGN(InteractiveUpdateRequestedVariable);
382};
383
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700384// RealUpdaterProvider methods.
385
386RealUpdaterProvider::RealUpdaterProvider(SystemState* system_state)
387 : system_state_(system_state),
Alex Deymoc7ab6162014-04-25 18:32:50 -0700388 var_updater_started_time_("updater_started_time",
389 system_state->clock()->GetWallclockTime()),
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700390 var_last_checked_time_(
391 new LastCheckedTimeVariable("last_checked_time", system_state_)),
392 var_update_completed_time_(
393 new UpdateCompletedTimeVariable("update_completed_time",
394 system_state_)),
395 var_progress_(new ProgressVariable("progress", system_state_)),
396 var_stage_(new StageVariable("stage", system_state_)),
397 var_new_version_(new NewVersionVariable("new_version", system_state_)),
398 var_payload_size_(new PayloadSizeVariable("payload_size", system_state_)),
399 var_curr_channel_(new CurrChannelVariable("curr_channel", system_state_)),
400 var_new_channel_(new NewChannelVariable("new_channel", system_state_)),
401 var_p2p_enabled_(
402 new BooleanPrefVariable("p2p_enabled", system_state_,
403 chromeos_update_engine::kPrefsP2PEnabled,
404 false)),
405 var_cellular_enabled_(
406 new BooleanPrefVariable(
407 "cellular_enabled", system_state_,
408 chromeos_update_engine::kPrefsUpdateOverCellularPermission,
Gilad Arnolda6dab942014-04-25 11:46:03 -0700409 false)),
410 var_consecutive_failed_update_checks_(
411 new ConsecutiveFailedUpdateChecksVariable(
Gilad Arnolda0258a52014-07-10 16:21:19 -0700412 "consecutive_failed_update_checks", system_state_)),
413 var_server_dictated_poll_interval_(
414 new ServerDictatedPollIntervalVariable(
Gilad Arnold44dc3bf2014-07-18 23:39:38 -0700415 "server_dictated_poll_interval", system_state_)),
416 var_interactive_update_requested_(
417 new InteractiveUpdateRequestedVariable(
418 "interactive_update_requested", system_state_)) {}
Gilad Arnoldae47a9a2014-03-26 12:16:47 -0700419
Alex Deymo63784a52014-05-28 10:46:14 -0700420} // namespace chromeos_update_manager