1 //
2 // Copyright (C) 2014 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "update_engine/update_manager/real_updater_provider.h"
18
19 #include <inttypes.h>
20
21 #include <string>
22
23 #include <base/bind.h>
24 #include <base/strings/stringprintf.h>
25 #include <base/time/time.h>
26 #include <update_engine/dbus-constants.h>
27
28 #include "update_engine/common/clock_interface.h"
29 #include "update_engine/common/prefs.h"
30 #include "update_engine/omaha_request_params.h"
31 #include "update_engine/update_attempter.h"
32
33 using base::StringPrintf;
34 using base::Time;
35 using base::TimeDelta;
36 using chromeos_update_engine::OmahaRequestParams;
37 using chromeos_update_engine::SystemState;
38 using std::string;
39
40 namespace chromeos_update_manager {
41
42 // A templated base class for all update related variables. Provides uniform
43 // construction and a system state handle.
44 template<typename T>
45 class UpdaterVariableBase : public Variable<T> {
46 public:
UpdaterVariableBase(const string & name,VariableMode mode,SystemState * system_state)47 UpdaterVariableBase(const string& name, VariableMode mode,
48 SystemState* system_state)
49 : Variable<T>(name, mode), system_state_(system_state) {}
50
51 protected:
52 // The system state used for pulling information from the updater.
system_state() const53 inline SystemState* system_state() const { return system_state_; }
54
55 private:
56 SystemState* const system_state_;
57 };
58
59 // Helper class for issuing a GetStatus() to the UpdateAttempter.
60 class GetStatusHelper {
61 public:
GetStatusHelper(SystemState * system_state,string * errmsg)62 GetStatusHelper(SystemState* system_state, string* errmsg) {
63 is_success_ = system_state->update_attempter()->GetStatus(
64 &last_checked_time_, &progress_, &update_status_, &new_version_,
65 &payload_size_);
66 if (!is_success_ && errmsg)
67 *errmsg = "Failed to get a status update from the update engine";
68 }
69
is_success()70 inline bool is_success() { return is_success_; }
last_checked_time()71 inline int64_t last_checked_time() { return last_checked_time_; }
progress()72 inline double progress() { return progress_; }
update_status()73 inline const string& update_status() { return update_status_; }
new_version()74 inline const string& new_version() { return new_version_; }
payload_size()75 inline int64_t payload_size() { return payload_size_; }
76
77 private:
78 bool is_success_;
79 int64_t last_checked_time_;
80 double progress_;
81 string update_status_;
82 string new_version_;
83 int64_t payload_size_;
84 };
85
86 // A variable reporting the time when a last update check was issued.
87 class LastCheckedTimeVariable : public UpdaterVariableBase<Time> {
88 public:
LastCheckedTimeVariable(const string & name,SystemState * system_state)89 LastCheckedTimeVariable(const string& name, SystemState* system_state)
90 : UpdaterVariableBase<Time>(name, kVariableModePoll, system_state) {}
91
92 private:
GetValue(TimeDelta,string * errmsg)93 const Time* GetValue(TimeDelta /* timeout */, string* errmsg) override {
94 GetStatusHelper raw(system_state(), errmsg);
95 if (!raw.is_success())
96 return nullptr;
97
98 return new Time(Time::FromTimeT(raw.last_checked_time()));
99 }
100
101 DISALLOW_COPY_AND_ASSIGN(LastCheckedTimeVariable);
102 };
103
104 // A variable reporting the update (download) progress as a decimal fraction
105 // between 0.0 and 1.0.
106 class ProgressVariable : public UpdaterVariableBase<double> {
107 public:
ProgressVariable(const string & name,SystemState * system_state)108 ProgressVariable(const string& name, SystemState* system_state)
109 : UpdaterVariableBase<double>(name, kVariableModePoll, system_state) {}
110
111 private:
GetValue(TimeDelta,string * errmsg)112 const double* GetValue(TimeDelta /* timeout */, string* errmsg) override {
113 GetStatusHelper raw(system_state(), errmsg);
114 if (!raw.is_success())
115 return nullptr;
116
117 if (raw.progress() < 0.0 || raw.progress() > 1.0) {
118 if (errmsg) {
119 *errmsg = StringPrintf("Invalid progress value received: %f",
120 raw.progress());
121 }
122 return nullptr;
123 }
124
125 return new double(raw.progress());
126 }
127
128 DISALLOW_COPY_AND_ASSIGN(ProgressVariable);
129 };
130
131 // A variable reporting the stage in which the update process is.
132 class StageVariable : public UpdaterVariableBase<Stage> {
133 public:
StageVariable(const string & name,SystemState * system_state)134 StageVariable(const string& name, SystemState* system_state)
135 : UpdaterVariableBase<Stage>(name, kVariableModePoll, system_state) {}
136
137 private:
138 struct CurrOpStrToStage {
139 const char* str;
140 Stage stage;
141 };
142 static const CurrOpStrToStage curr_op_str_to_stage[];
143
144 // Note: the method is defined outside the class so arraysize can work.
145 const Stage* GetValue(TimeDelta /* timeout */, string* errmsg) override;
146
147 DISALLOW_COPY_AND_ASSIGN(StageVariable);
148 };
149
150 const StageVariable::CurrOpStrToStage StageVariable::curr_op_str_to_stage[] = {
151 {update_engine::kUpdateStatusIdle, Stage::kIdle},
152 {update_engine::kUpdateStatusCheckingForUpdate, Stage::kCheckingForUpdate},
153 {update_engine::kUpdateStatusUpdateAvailable, Stage::kUpdateAvailable},
154 {update_engine::kUpdateStatusDownloading, Stage::kDownloading},
155 {update_engine::kUpdateStatusVerifying, Stage::kVerifying},
156 {update_engine::kUpdateStatusFinalizing, Stage::kFinalizing},
157 {update_engine::kUpdateStatusUpdatedNeedReboot, Stage::kUpdatedNeedReboot},
158 { // NOLINT(whitespace/braces)
159 update_engine::kUpdateStatusReportingErrorEvent,
160 Stage::kReportingErrorEvent
161 },
162 {update_engine::kUpdateStatusAttemptingRollback, Stage::kAttemptingRollback},
163 };
164
GetValue(TimeDelta,string * errmsg)165 const Stage* StageVariable::GetValue(TimeDelta /* timeout */,
166 string* errmsg) {
167 GetStatusHelper raw(system_state(), errmsg);
168 if (!raw.is_success())
169 return nullptr;
170
171 for (auto& key_val : curr_op_str_to_stage)
172 if (raw.update_status() == key_val.str)
173 return new Stage(key_val.stage);
174
175 if (errmsg)
176 *errmsg = string("Unknown update status: ") + raw.update_status();
177 return nullptr;
178 }
179
180 // A variable reporting the version number that an update is updating to.
181 class NewVersionVariable : public UpdaterVariableBase<string> {
182 public:
NewVersionVariable(const string & name,SystemState * system_state)183 NewVersionVariable(const string& name, SystemState* system_state)
184 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {}
185
186 private:
GetValue(TimeDelta,string * errmsg)187 const string* GetValue(TimeDelta /* timeout */, string* errmsg) override {
188 GetStatusHelper raw(system_state(), errmsg);
189 if (!raw.is_success())
190 return nullptr;
191
192 return new string(raw.new_version());
193 }
194
195 DISALLOW_COPY_AND_ASSIGN(NewVersionVariable);
196 };
197
198 // A variable reporting the size of the update being processed in bytes.
199 class PayloadSizeVariable : public UpdaterVariableBase<int64_t> {
200 public:
PayloadSizeVariable(const string & name,SystemState * system_state)201 PayloadSizeVariable(const string& name, SystemState* system_state)
202 : UpdaterVariableBase<int64_t>(name, kVariableModePoll, system_state) {}
203
204 private:
GetValue(TimeDelta,string * errmsg)205 const int64_t* GetValue(TimeDelta /* timeout */, string* errmsg) override {
206 GetStatusHelper raw(system_state(), errmsg);
207 if (!raw.is_success())
208 return nullptr;
209
210 if (raw.payload_size() < 0) {
211 if (errmsg)
212 *errmsg = string("Invalid payload size: %" PRId64, raw.payload_size());
213 return nullptr;
214 }
215
216 return new int64_t(raw.payload_size());
217 }
218
219 DISALLOW_COPY_AND_ASSIGN(PayloadSizeVariable);
220 };
221
222 // A variable reporting the point in time an update last completed in the
223 // current boot cycle.
224 //
225 // TODO(garnold) In general, both the current boottime and wallclock time
226 // readings should come from the time provider and be moderated by the
227 // evaluation context, so that they are uniform throughout the evaluation of a
228 // policy request.
229 class UpdateCompletedTimeVariable : public UpdaterVariableBase<Time> {
230 public:
UpdateCompletedTimeVariable(const string & name,SystemState * system_state)231 UpdateCompletedTimeVariable(const string& name, SystemState* system_state)
232 : UpdaterVariableBase<Time>(name, kVariableModePoll, system_state) {}
233
234 private:
GetValue(TimeDelta,string * errmsg)235 const Time* GetValue(TimeDelta /* timeout */, string* errmsg) override {
236 Time update_boottime;
237 if (!system_state()->update_attempter()->GetBootTimeAtUpdate(
238 &update_boottime)) {
239 if (errmsg)
240 *errmsg = "Update completed time could not be read";
241 return nullptr;
242 }
243
244 chromeos_update_engine::ClockInterface* clock = system_state()->clock();
245 Time curr_boottime = clock->GetBootTime();
246 if (curr_boottime < update_boottime) {
247 if (errmsg)
248 *errmsg = "Update completed time more recent than current time";
249 return nullptr;
250 }
251 TimeDelta duration_since_update = curr_boottime - update_boottime;
252 return new Time(clock->GetWallclockTime() - duration_since_update);
253 }
254
255 DISALLOW_COPY_AND_ASSIGN(UpdateCompletedTimeVariable);
256 };
257
258 // Variables reporting the current image channel.
259 class CurrChannelVariable : public UpdaterVariableBase<string> {
260 public:
CurrChannelVariable(const string & name,SystemState * system_state)261 CurrChannelVariable(const string& name, SystemState* system_state)
262 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {}
263
264 private:
GetValue(TimeDelta,string * errmsg)265 const string* GetValue(TimeDelta /* timeout */, string* errmsg) override {
266 OmahaRequestParams* request_params = system_state()->request_params();
267 string channel = request_params->current_channel();
268 if (channel.empty()) {
269 if (errmsg)
270 *errmsg = "No current channel";
271 return nullptr;
272 }
273 return new string(channel);
274 }
275
276 DISALLOW_COPY_AND_ASSIGN(CurrChannelVariable);
277 };
278
279 // Variables reporting the new image channel.
280 class NewChannelVariable : public UpdaterVariableBase<string> {
281 public:
NewChannelVariable(const string & name,SystemState * system_state)282 NewChannelVariable(const string& name, SystemState* system_state)
283 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {}
284
285 private:
GetValue(TimeDelta,string * errmsg)286 const string* GetValue(TimeDelta /* timeout */, string* errmsg) override {
287 OmahaRequestParams* request_params = system_state()->request_params();
288 string channel = request_params->target_channel();
289 if (channel.empty()) {
290 if (errmsg)
291 *errmsg = "No new channel";
292 return nullptr;
293 }
294 return new string(channel);
295 }
296
297 DISALLOW_COPY_AND_ASSIGN(NewChannelVariable);
298 };
299
300 // A variable class for reading Boolean prefs values.
301 class BooleanPrefVariable
302 : public AsyncCopyVariable<bool>,
303 public chromeos_update_engine::PrefsInterface::ObserverInterface {
304 public:
BooleanPrefVariable(const string & name,chromeos_update_engine::PrefsInterface * prefs,const char * key,bool default_val)305 BooleanPrefVariable(const string& name,
306 chromeos_update_engine::PrefsInterface* prefs,
307 const char* key,
308 bool default_val)
309 : AsyncCopyVariable<bool>(name),
310 prefs_(prefs),
311 key_(key),
312 default_val_(default_val) {
313 prefs->AddObserver(key, this);
314 OnPrefSet(key);
315 }
~BooleanPrefVariable()316 ~BooleanPrefVariable() {
317 prefs_->RemoveObserver(key_, this);
318 }
319
320 private:
321 // Reads the actual value from the Prefs instance and updates the Variable
322 // value.
OnPrefSet(const string & key)323 void OnPrefSet(const string& key) override {
324 bool result = default_val_;
325 if (prefs_ && prefs_->Exists(key_) && !prefs_->GetBoolean(key_, &result))
326 result = default_val_;
327 // AsyncCopyVariable will take care of values that didn't change.
328 SetValue(result);
329 }
330
OnPrefDeleted(const string & key)331 void OnPrefDeleted(const string& key) override {
332 SetValue(default_val_);
333 }
334
335 chromeos_update_engine::PrefsInterface* prefs_;
336
337 // The Boolean preference key and default value.
338 const char* const key_;
339 const bool default_val_;
340
341 DISALLOW_COPY_AND_ASSIGN(BooleanPrefVariable);
342 };
343
344 // A variable returning the number of consecutive failed update checks.
345 class ConsecutiveFailedUpdateChecksVariable
346 : public UpdaterVariableBase<unsigned int> {
347 public:
ConsecutiveFailedUpdateChecksVariable(const string & name,SystemState * system_state)348 ConsecutiveFailedUpdateChecksVariable(const string& name,
349 SystemState* system_state)
350 : UpdaterVariableBase<unsigned int>(name, kVariableModePoll,
351 system_state) {}
352
353 private:
GetValue(TimeDelta,string *)354 const unsigned int* GetValue(TimeDelta /* timeout */,
355 string* /* errmsg */) override {
356 return new unsigned int(
357 system_state()->update_attempter()->consecutive_failed_update_checks());
358 }
359
360 DISALLOW_COPY_AND_ASSIGN(ConsecutiveFailedUpdateChecksVariable);
361 };
362
363 // A variable returning the server-dictated poll interval.
364 class ServerDictatedPollIntervalVariable
365 : public UpdaterVariableBase<unsigned int> {
366 public:
ServerDictatedPollIntervalVariable(const string & name,SystemState * system_state)367 ServerDictatedPollIntervalVariable(const string& name,
368 SystemState* system_state)
369 : UpdaterVariableBase<unsigned int>(name, kVariableModePoll,
370 system_state) {}
371
372 private:
GetValue(TimeDelta,string *)373 const unsigned int* GetValue(TimeDelta /* timeout */,
374 string* /* errmsg */) override {
375 return new unsigned int(
376 system_state()->update_attempter()->server_dictated_poll_interval());
377 }
378
379 DISALLOW_COPY_AND_ASSIGN(ServerDictatedPollIntervalVariable);
380 };
381
382 // An async variable that tracks changes to forced update requests.
383 class ForcedUpdateRequestedVariable
384 : public UpdaterVariableBase<UpdateRequestStatus> {
385 public:
ForcedUpdateRequestedVariable(const string & name,SystemState * system_state)386 ForcedUpdateRequestedVariable(const string& name, SystemState* system_state)
387 : UpdaterVariableBase<UpdateRequestStatus>::UpdaterVariableBase(
388 name, kVariableModeAsync, system_state) {
389 system_state->update_attempter()->set_forced_update_pending_callback(
390 new base::Callback<void(bool, bool)>( // NOLINT(readability/function)
391 base::Bind(&ForcedUpdateRequestedVariable::Reset,
392 base::Unretained(this))));
393 }
394
395 private:
GetValue(TimeDelta,string *)396 const UpdateRequestStatus* GetValue(TimeDelta /* timeout */,
397 string* /* errmsg */) override {
398 return new UpdateRequestStatus(update_request_status_);
399 }
400
Reset(bool forced_update_requested,bool is_interactive)401 void Reset(bool forced_update_requested, bool is_interactive) {
402 UpdateRequestStatus new_value = UpdateRequestStatus::kNone;
403 if (forced_update_requested)
404 new_value = (is_interactive ? UpdateRequestStatus::kInteractive :
405 UpdateRequestStatus::kPeriodic);
406 if (update_request_status_ != new_value) {
407 update_request_status_ = new_value;
408 NotifyValueChanged();
409 }
410 }
411
412 UpdateRequestStatus update_request_status_ = UpdateRequestStatus::kNone;
413
414 DISALLOW_COPY_AND_ASSIGN(ForcedUpdateRequestedVariable);
415 };
416
417 // RealUpdaterProvider methods.
418
RealUpdaterProvider(SystemState * system_state)419 RealUpdaterProvider::RealUpdaterProvider(SystemState* system_state)
420 : system_state_(system_state),
421 var_updater_started_time_("updater_started_time",
422 system_state->clock()->GetWallclockTime()),
423 var_last_checked_time_(
424 new LastCheckedTimeVariable("last_checked_time", system_state_)),
425 var_update_completed_time_(
426 new UpdateCompletedTimeVariable("update_completed_time",
427 system_state_)),
428 var_progress_(new ProgressVariable("progress", system_state_)),
429 var_stage_(new StageVariable("stage", system_state_)),
430 var_new_version_(new NewVersionVariable("new_version", system_state_)),
431 var_payload_size_(new PayloadSizeVariable("payload_size", system_state_)),
432 var_curr_channel_(new CurrChannelVariable("curr_channel", system_state_)),
433 var_new_channel_(new NewChannelVariable("new_channel", system_state_)),
434 var_p2p_enabled_(
435 new BooleanPrefVariable("p2p_enabled", system_state_->prefs(),
436 chromeos_update_engine::kPrefsP2PEnabled,
437 false)),
438 var_cellular_enabled_(
439 new BooleanPrefVariable(
440 "cellular_enabled", system_state_->prefs(),
441 chromeos_update_engine::kPrefsUpdateOverCellularPermission,
442 false)),
443 var_consecutive_failed_update_checks_(
444 new ConsecutiveFailedUpdateChecksVariable(
445 "consecutive_failed_update_checks", system_state_)),
446 var_server_dictated_poll_interval_(
447 new ServerDictatedPollIntervalVariable(
448 "server_dictated_poll_interval", system_state_)),
449 var_forced_update_requested_(
450 new ForcedUpdateRequestedVariable(
451 "forced_update_requested", system_state_)) {}
452
453 } // namespace chromeos_update_manager
454