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