|  | // | 
|  | // Copyright (C) 2014 The Android Open Source Project | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  | // | 
|  |  | 
|  | #include "update_engine/update_manager/real_updater_provider.h" | 
|  |  | 
|  | #include <inttypes.h> | 
|  |  | 
|  | #include <string> | 
|  |  | 
|  | #include <base/bind.h> | 
|  | #include <base/strings/stringprintf.h> | 
|  | #include <base/time/time.h> | 
|  | #include <update_engine/dbus-constants.h> | 
|  |  | 
|  | #include "update_engine/common/clock_interface.h" | 
|  | #include "update_engine/common/prefs.h" | 
|  | #include "update_engine/omaha_request_params.h" | 
|  | #include "update_engine/update_attempter.h" | 
|  |  | 
|  | using base::StringPrintf; | 
|  | using base::Time; | 
|  | using base::TimeDelta; | 
|  | using chromeos_update_engine::OmahaRequestParams; | 
|  | using chromeos_update_engine::SystemState; | 
|  | using std::string; | 
|  |  | 
|  | namespace chromeos_update_manager { | 
|  |  | 
|  | // A templated base class for all update related variables. Provides uniform | 
|  | // construction and a system state handle. | 
|  | template<typename T> | 
|  | class UpdaterVariableBase : public Variable<T> { | 
|  | public: | 
|  | UpdaterVariableBase(const string& name, VariableMode mode, | 
|  | SystemState* system_state) | 
|  | : Variable<T>(name, mode), system_state_(system_state) {} | 
|  |  | 
|  | protected: | 
|  | // The system state used for pulling information from the updater. | 
|  | inline SystemState* system_state() const { return system_state_; } | 
|  |  | 
|  | private: | 
|  | SystemState* const system_state_; | 
|  | }; | 
|  |  | 
|  | // Helper class for issuing a GetStatus() to the UpdateAttempter. | 
|  | class GetStatusHelper { | 
|  | public: | 
|  | GetStatusHelper(SystemState* system_state, string* errmsg) { | 
|  | is_success_ = system_state->update_attempter()->GetStatus( | 
|  | &last_checked_time_, &progress_, &update_status_, &new_version_, | 
|  | &payload_size_); | 
|  | if (!is_success_ && errmsg) | 
|  | *errmsg = "Failed to get a status update from the update engine"; | 
|  | } | 
|  |  | 
|  | inline bool is_success() { return is_success_; } | 
|  | inline int64_t last_checked_time() { return last_checked_time_; } | 
|  | inline double progress() { return progress_; } | 
|  | inline const string& update_status() { return update_status_; } | 
|  | inline const string& new_version() { return new_version_; } | 
|  | inline int64_t payload_size() { return payload_size_; } | 
|  |  | 
|  | private: | 
|  | bool is_success_; | 
|  | int64_t last_checked_time_; | 
|  | double progress_; | 
|  | string update_status_; | 
|  | string new_version_; | 
|  | int64_t payload_size_; | 
|  | }; | 
|  |  | 
|  | // A variable reporting the time when a last update check was issued. | 
|  | class LastCheckedTimeVariable : public UpdaterVariableBase<Time> { | 
|  | public: | 
|  | LastCheckedTimeVariable(const string& name, SystemState* system_state) | 
|  | : UpdaterVariableBase<Time>(name, kVariableModePoll, system_state) {} | 
|  |  | 
|  | private: | 
|  | const Time* GetValue(TimeDelta /* timeout */, string* errmsg) override { | 
|  | GetStatusHelper raw(system_state(), errmsg); | 
|  | if (!raw.is_success()) | 
|  | return nullptr; | 
|  |  | 
|  | return new Time(Time::FromTimeT(raw.last_checked_time())); | 
|  | } | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(LastCheckedTimeVariable); | 
|  | }; | 
|  |  | 
|  | // A variable reporting the update (download) progress as a decimal fraction | 
|  | // between 0.0 and 1.0. | 
|  | class ProgressVariable : public UpdaterVariableBase<double> { | 
|  | public: | 
|  | ProgressVariable(const string& name, SystemState* system_state) | 
|  | : UpdaterVariableBase<double>(name, kVariableModePoll, system_state) {} | 
|  |  | 
|  | private: | 
|  | const double* GetValue(TimeDelta /* timeout */, string* errmsg) override { | 
|  | GetStatusHelper raw(system_state(), errmsg); | 
|  | if (!raw.is_success()) | 
|  | return nullptr; | 
|  |  | 
|  | if (raw.progress() < 0.0 || raw.progress() > 1.0) { | 
|  | if (errmsg) { | 
|  | *errmsg = StringPrintf("Invalid progress value received: %f", | 
|  | raw.progress()); | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return new double(raw.progress()); | 
|  | } | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ProgressVariable); | 
|  | }; | 
|  |  | 
|  | // A variable reporting the stage in which the update process is. | 
|  | class StageVariable : public UpdaterVariableBase<Stage> { | 
|  | public: | 
|  | StageVariable(const string& name, SystemState* system_state) | 
|  | : UpdaterVariableBase<Stage>(name, kVariableModePoll, system_state) {} | 
|  |  | 
|  | private: | 
|  | struct CurrOpStrToStage { | 
|  | const char* str; | 
|  | Stage stage; | 
|  | }; | 
|  | static const CurrOpStrToStage curr_op_str_to_stage[]; | 
|  |  | 
|  | // Note: the method is defined outside the class so arraysize can work. | 
|  | const Stage* GetValue(TimeDelta /* timeout */, string* errmsg) override; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(StageVariable); | 
|  | }; | 
|  |  | 
|  | const StageVariable::CurrOpStrToStage StageVariable::curr_op_str_to_stage[] = { | 
|  | {update_engine::kUpdateStatusIdle, Stage::kIdle}, | 
|  | {update_engine::kUpdateStatusCheckingForUpdate, Stage::kCheckingForUpdate}, | 
|  | {update_engine::kUpdateStatusUpdateAvailable, Stage::kUpdateAvailable}, | 
|  | {update_engine::kUpdateStatusDownloading, Stage::kDownloading}, | 
|  | {update_engine::kUpdateStatusVerifying, Stage::kVerifying}, | 
|  | {update_engine::kUpdateStatusFinalizing, Stage::kFinalizing}, | 
|  | {update_engine::kUpdateStatusUpdatedNeedReboot, Stage::kUpdatedNeedReboot}, | 
|  | {  // NOLINT(whitespace/braces) | 
|  | update_engine::kUpdateStatusReportingErrorEvent, | 
|  | Stage::kReportingErrorEvent | 
|  | }, | 
|  | {update_engine::kUpdateStatusAttemptingRollback, Stage::kAttemptingRollback}, | 
|  | }; | 
|  |  | 
|  | const Stage* StageVariable::GetValue(TimeDelta /* timeout */, | 
|  | string* errmsg) { | 
|  | GetStatusHelper raw(system_state(), errmsg); | 
|  | if (!raw.is_success()) | 
|  | return nullptr; | 
|  |  | 
|  | for (auto& key_val : curr_op_str_to_stage) | 
|  | if (raw.update_status() == key_val.str) | 
|  | return new Stage(key_val.stage); | 
|  |  | 
|  | if (errmsg) | 
|  | *errmsg = string("Unknown update status: ") + raw.update_status(); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // A variable reporting the version number that an update is updating to. | 
|  | class NewVersionVariable : public UpdaterVariableBase<string> { | 
|  | public: | 
|  | NewVersionVariable(const string& name, SystemState* system_state) | 
|  | : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {} | 
|  |  | 
|  | private: | 
|  | const string* GetValue(TimeDelta /* timeout */, string* errmsg) override { | 
|  | GetStatusHelper raw(system_state(), errmsg); | 
|  | if (!raw.is_success()) | 
|  | return nullptr; | 
|  |  | 
|  | return new string(raw.new_version()); | 
|  | } | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(NewVersionVariable); | 
|  | }; | 
|  |  | 
|  | // A variable reporting the size of the update being processed in bytes. | 
|  | class PayloadSizeVariable : public UpdaterVariableBase<int64_t> { | 
|  | public: | 
|  | PayloadSizeVariable(const string& name, SystemState* system_state) | 
|  | : UpdaterVariableBase<int64_t>(name, kVariableModePoll, system_state) {} | 
|  |  | 
|  | private: | 
|  | const int64_t* GetValue(TimeDelta /* timeout */, string* errmsg) override { | 
|  | GetStatusHelper raw(system_state(), errmsg); | 
|  | if (!raw.is_success()) | 
|  | return nullptr; | 
|  |  | 
|  | if (raw.payload_size() < 0) { | 
|  | if (errmsg) | 
|  | *errmsg = string("Invalid payload size: %" PRId64, raw.payload_size()); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return new int64_t(raw.payload_size()); | 
|  | } | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(PayloadSizeVariable); | 
|  | }; | 
|  |  | 
|  | // A variable reporting the point in time an update last completed in the | 
|  | // current boot cycle. | 
|  | // | 
|  | // TODO(garnold) In general, both the current boottime and wallclock time | 
|  | // readings should come from the time provider and be moderated by the | 
|  | // evaluation context, so that they are uniform throughout the evaluation of a | 
|  | // policy request. | 
|  | class UpdateCompletedTimeVariable : public UpdaterVariableBase<Time> { | 
|  | public: | 
|  | UpdateCompletedTimeVariable(const string& name, SystemState* system_state) | 
|  | : UpdaterVariableBase<Time>(name, kVariableModePoll, system_state) {} | 
|  |  | 
|  | private: | 
|  | const Time* GetValue(TimeDelta /* timeout */, string* errmsg) override { | 
|  | Time update_boottime; | 
|  | if (!system_state()->update_attempter()->GetBootTimeAtUpdate( | 
|  | &update_boottime)) { | 
|  | if (errmsg) | 
|  | *errmsg = "Update completed time could not be read"; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | chromeos_update_engine::ClockInterface* clock = system_state()->clock(); | 
|  | Time curr_boottime = clock->GetBootTime(); | 
|  | if (curr_boottime < update_boottime) { | 
|  | if (errmsg) | 
|  | *errmsg = "Update completed time more recent than current time"; | 
|  | return nullptr; | 
|  | } | 
|  | TimeDelta duration_since_update = curr_boottime - update_boottime; | 
|  | return new Time(clock->GetWallclockTime() - duration_since_update); | 
|  | } | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(UpdateCompletedTimeVariable); | 
|  | }; | 
|  |  | 
|  | // Variables reporting the current image channel. | 
|  | class CurrChannelVariable : public UpdaterVariableBase<string> { | 
|  | public: | 
|  | CurrChannelVariable(const string& name, SystemState* system_state) | 
|  | : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {} | 
|  |  | 
|  | private: | 
|  | const string* GetValue(TimeDelta /* timeout */, string* errmsg) override { | 
|  | OmahaRequestParams* request_params = system_state()->request_params(); | 
|  | string channel = request_params->current_channel(); | 
|  | if (channel.empty()) { | 
|  | if (errmsg) | 
|  | *errmsg = "No current channel"; | 
|  | return nullptr; | 
|  | } | 
|  | return new string(channel); | 
|  | } | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(CurrChannelVariable); | 
|  | }; | 
|  |  | 
|  | // Variables reporting the new image channel. | 
|  | class NewChannelVariable : public UpdaterVariableBase<string> { | 
|  | public: | 
|  | NewChannelVariable(const string& name, SystemState* system_state) | 
|  | : UpdaterVariableBase<string>(name, kVariableModePoll, system_state) {} | 
|  |  | 
|  | private: | 
|  | const string* GetValue(TimeDelta /* timeout */, string* errmsg) override { | 
|  | OmahaRequestParams* request_params = system_state()->request_params(); | 
|  | string channel = request_params->target_channel(); | 
|  | if (channel.empty()) { | 
|  | if (errmsg) | 
|  | *errmsg = "No new channel"; | 
|  | return nullptr; | 
|  | } | 
|  | return new string(channel); | 
|  | } | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(NewChannelVariable); | 
|  | }; | 
|  |  | 
|  | // A variable class for reading Boolean prefs values. | 
|  | class BooleanPrefVariable | 
|  | : public AsyncCopyVariable<bool>, | 
|  | public chromeos_update_engine::PrefsInterface::ObserverInterface { | 
|  | public: | 
|  | BooleanPrefVariable(const string& name, | 
|  | chromeos_update_engine::PrefsInterface* prefs, | 
|  | const char* key, | 
|  | bool default_val) | 
|  | : AsyncCopyVariable<bool>(name), | 
|  | prefs_(prefs), | 
|  | key_(key), | 
|  | default_val_(default_val) { | 
|  | prefs->AddObserver(key, this); | 
|  | OnPrefSet(key); | 
|  | } | 
|  | ~BooleanPrefVariable() { | 
|  | prefs_->RemoveObserver(key_, this); | 
|  | } | 
|  |  | 
|  | private: | 
|  | // Reads the actual value from the Prefs instance and updates the Variable | 
|  | // value. | 
|  | void OnPrefSet(const string& key) override { | 
|  | bool result = default_val_; | 
|  | if (prefs_ && prefs_->Exists(key_) && !prefs_->GetBoolean(key_, &result)) | 
|  | result = default_val_; | 
|  | // AsyncCopyVariable will take care of values that didn't change. | 
|  | SetValue(result); | 
|  | } | 
|  |  | 
|  | void OnPrefDeleted(const string& key) override { | 
|  | SetValue(default_val_); | 
|  | } | 
|  |  | 
|  | chromeos_update_engine::PrefsInterface* prefs_; | 
|  |  | 
|  | // The Boolean preference key and default value. | 
|  | const char* const key_; | 
|  | const bool default_val_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(BooleanPrefVariable); | 
|  | }; | 
|  |  | 
|  | // A variable returning the number of consecutive failed update checks. | 
|  | class ConsecutiveFailedUpdateChecksVariable | 
|  | : public UpdaterVariableBase<unsigned int> { | 
|  | public: | 
|  | ConsecutiveFailedUpdateChecksVariable(const string& name, | 
|  | SystemState* system_state) | 
|  | : UpdaterVariableBase<unsigned int>(name, kVariableModePoll, | 
|  | system_state) {} | 
|  |  | 
|  | private: | 
|  | const unsigned int* GetValue(TimeDelta /* timeout */, | 
|  | string* /* errmsg */) override { | 
|  | return new unsigned int( | 
|  | system_state()->update_attempter()->consecutive_failed_update_checks()); | 
|  | } | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ConsecutiveFailedUpdateChecksVariable); | 
|  | }; | 
|  |  | 
|  | // A variable returning the server-dictated poll interval. | 
|  | class ServerDictatedPollIntervalVariable | 
|  | : public UpdaterVariableBase<unsigned int> { | 
|  | public: | 
|  | ServerDictatedPollIntervalVariable(const string& name, | 
|  | SystemState* system_state) | 
|  | : UpdaterVariableBase<unsigned int>(name, kVariableModePoll, | 
|  | system_state) {} | 
|  |  | 
|  | private: | 
|  | const unsigned int* GetValue(TimeDelta /* timeout */, | 
|  | string* /* errmsg */) override { | 
|  | return new unsigned int( | 
|  | system_state()->update_attempter()->server_dictated_poll_interval()); | 
|  | } | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ServerDictatedPollIntervalVariable); | 
|  | }; | 
|  |  | 
|  | // An async variable that tracks changes to forced update requests. | 
|  | class ForcedUpdateRequestedVariable | 
|  | : public UpdaterVariableBase<UpdateRequestStatus> { | 
|  | public: | 
|  | ForcedUpdateRequestedVariable(const string& name, SystemState* system_state) | 
|  | : UpdaterVariableBase<UpdateRequestStatus>::UpdaterVariableBase( | 
|  | name, kVariableModeAsync, system_state) { | 
|  | system_state->update_attempter()->set_forced_update_pending_callback( | 
|  | new base::Callback<void(bool, bool)>(  // NOLINT(readability/function) | 
|  | base::Bind(&ForcedUpdateRequestedVariable::Reset, | 
|  | base::Unretained(this)))); | 
|  | } | 
|  |  | 
|  | private: | 
|  | const UpdateRequestStatus* GetValue(TimeDelta /* timeout */, | 
|  | string* /* errmsg */) override { | 
|  | return new UpdateRequestStatus(update_request_status_); | 
|  | } | 
|  |  | 
|  | void Reset(bool forced_update_requested, bool is_interactive) { | 
|  | UpdateRequestStatus new_value = UpdateRequestStatus::kNone; | 
|  | if (forced_update_requested) | 
|  | new_value = (is_interactive ? UpdateRequestStatus::kInteractive : | 
|  | UpdateRequestStatus::kPeriodic); | 
|  | if (update_request_status_ != new_value) { | 
|  | update_request_status_ = new_value; | 
|  | NotifyValueChanged(); | 
|  | } | 
|  | } | 
|  |  | 
|  | UpdateRequestStatus update_request_status_ = UpdateRequestStatus::kNone; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ForcedUpdateRequestedVariable); | 
|  | }; | 
|  |  | 
|  | // RealUpdaterProvider methods. | 
|  |  | 
|  | RealUpdaterProvider::RealUpdaterProvider(SystemState* system_state) | 
|  | : system_state_(system_state), | 
|  | var_updater_started_time_("updater_started_time", | 
|  | system_state->clock()->GetWallclockTime()), | 
|  | var_last_checked_time_( | 
|  | new LastCheckedTimeVariable("last_checked_time", system_state_)), | 
|  | var_update_completed_time_( | 
|  | new UpdateCompletedTimeVariable("update_completed_time", | 
|  | system_state_)), | 
|  | var_progress_(new ProgressVariable("progress", system_state_)), | 
|  | var_stage_(new StageVariable("stage", system_state_)), | 
|  | var_new_version_(new NewVersionVariable("new_version", system_state_)), | 
|  | var_payload_size_(new PayloadSizeVariable("payload_size", system_state_)), | 
|  | var_curr_channel_(new CurrChannelVariable("curr_channel", system_state_)), | 
|  | var_new_channel_(new NewChannelVariable("new_channel", system_state_)), | 
|  | var_p2p_enabled_( | 
|  | new BooleanPrefVariable("p2p_enabled", system_state_->prefs(), | 
|  | chromeos_update_engine::kPrefsP2PEnabled, | 
|  | false)), | 
|  | var_cellular_enabled_( | 
|  | new BooleanPrefVariable( | 
|  | "cellular_enabled", system_state_->prefs(), | 
|  | chromeos_update_engine::kPrefsUpdateOverCellularPermission, | 
|  | false)), | 
|  | var_consecutive_failed_update_checks_( | 
|  | new ConsecutiveFailedUpdateChecksVariable( | 
|  | "consecutive_failed_update_checks", system_state_)), | 
|  | var_server_dictated_poll_interval_( | 
|  | new ServerDictatedPollIntervalVariable( | 
|  | "server_dictated_poll_interval", system_state_)), | 
|  | var_forced_update_requested_( | 
|  | new ForcedUpdateRequestedVariable( | 
|  | "forced_update_requested", system_state_)) {} | 
|  |  | 
|  | }  // namespace chromeos_update_manager |