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: 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. 53 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: 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 70 inline bool is_success() { return is_success_; } 71 inline int64_t last_checked_time() { return last_checked_time_; } 72 inline double progress() { return progress_; } 73 inline const string& update_status() { return update_status_; } 74 inline const string& new_version() { return new_version_; } 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: 89 LastCheckedTimeVariable(const string& name, SystemState* system_state) 90 : UpdaterVariableBase<Time>(name, kVariableModePoll, system_state) {} 91 92 private: 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: 108 ProgressVariable(const string& name, SystemState* system_state) 109 : UpdaterVariableBase<double>(name, kVariableModePoll, system_state) {} 110 111 private: 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: 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 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: 183 NewVersionVariable(const string& name, SystemState* system_state) 184 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {} 185 186 private: 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: 201 PayloadSizeVariable(const string& name, SystemState* system_state) 202 : UpdaterVariableBase<int64_t>(name, kVariableModePoll, system_state) {} 203 204 private: 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: 231 UpdateCompletedTimeVariable(const string& name, SystemState* system_state) 232 : UpdaterVariableBase<Time>(name, kVariableModePoll, system_state) {} 233 234 private: 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: 261 CurrChannelVariable(const string& name, SystemState* system_state) 262 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {} 263 264 private: 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: 282 NewChannelVariable(const string& name, SystemState* system_state) 283 : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {} 284 285 private: 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: 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 } 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. 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 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: 348 ConsecutiveFailedUpdateChecksVariable(const string& name, 349 SystemState* system_state) 350 : UpdaterVariableBase<unsigned int>(name, kVariableModePoll, 351 system_state) {} 352 353 private: 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: 367 ServerDictatedPollIntervalVariable(const string& name, 368 SystemState* system_state) 369 : UpdaterVariableBase<unsigned int>(name, kVariableModePoll, 370 system_state) {} 371 372 private: 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: 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: 396 const UpdateRequestStatus* GetValue(TimeDelta /* timeout */, 397 string* /* errmsg */) override { 398 return new UpdateRequestStatus(update_request_status_); 399 } 400 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 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