// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef COMPONENTS_UPDATE_CLIENT_COMPONENT_H_ #define COMPONENTS_UPDATE_CLIENT_COMPONENT_H_ #include #include #include #include #include #include "base/callback.h" #include "base/files/file_path.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/threading/thread_checker.h" #include "base/time/time.h" #include "base/version.h" #include "components/update_client/crx_downloader.h" #include "components/update_client/protocol_parser.h" #include "components/update_client/update_client.h" #include "url/gurl.h" namespace update_client { struct CrxUpdateItem; struct UpdateContext; // Describes a CRX component managed by the UpdateEngine. Each |Component| is // associated with an UpdateContext. class Component { public: using Events = UpdateClient::Observer::Events; using CallbackHandleComplete = base::Callback; Component(const UpdateContext& update_context, const std::string& id); ~Component(); // Handles the current state of the component and makes it transition // to the next component state before |callback| is invoked. void Handle(CallbackHandleComplete callback); CrxUpdateItem GetCrxUpdateItem() const; // Called by the UpdateChecker to set the update response for this component. void SetParseResult(const ProtocolParser::Result& result); // Sets the uninstall state for this component. void Uninstall(const base::Version& cur_version, int reason); // Called by the UpdateEngine when an update check for this component is done. void UpdateCheckComplete() const; // Returns true if the component has reached a final state and no further // handling and state transitions are possible. bool IsHandled() const { return state_->IsFinal(); } // Returns true if an update is available for this component, meaning that // the update server has return a response containing an update. bool IsUpdateAvailable() const { return is_update_available_; } base::TimeDelta GetUpdateDuration() const; ComponentState state() const { return state_->state(); } std::string id() const { return id_; } const CrxComponent& crx_component() const { return crx_component_; } void set_crx_component(const CrxComponent& crx_component) { crx_component_ = crx_component; } const base::Version& previous_version() const { return previous_version_; } void set_previous_version(const base::Version& previous_version) { previous_version_ = previous_version; } const base::Version& next_version() const { return next_version_; } std::string previous_fp() const { return previous_fp_; } void set_previous_fp(const std::string& previous_fp) { previous_fp_ = previous_fp; } std::string next_fp() const { return next_fp_; } void set_next_fp(const std::string& next_fp) { next_fp_ = next_fp; } int update_check_error() const { return update_check_error_; } void set_update_check_error(int update_check_error) { update_check_error_ = update_check_error; } // Returns the time when processing of an update for this component has // begun, once the update has been discovered. Returns a null TimeTicks object // if the handling of an update has not happened. // base::TimeTicks update_begin() const { return update_begin_; } bool on_demand() const { return on_demand_; } void set_on_demand(bool on_demand) { on_demand_ = on_demand; } const std::vector& events() const { return events_; } const std::vector& crx_diffurls() const { return crx_diffurls_; } bool diff_update_failed() const { return !!diff_error_code_; } int error_category() const { return error_category_; } int error_code() const { return error_code_; } int extra_code1() const { return extra_code1_; } int diff_error_category() const { return diff_error_category_; } int diff_error_code() const { return diff_error_code_; } int diff_extra_code1() const { return diff_extra_code1_; } private: friend class FakePingManagerImpl; friend class UpdateCheckerTest; FRIEND_TEST_ALL_PREFIXES(PingManagerTest, SendPing); FRIEND_TEST_ALL_PREFIXES(PingManagerTest, RequiresEncryption); FRIEND_TEST_ALL_PREFIXES(UpdateCheckerTest, NoUpdateActionRun); FRIEND_TEST_ALL_PREFIXES(UpdateCheckerTest, UpdateCheckCupError); FRIEND_TEST_ALL_PREFIXES(UpdateCheckerTest, UpdateCheckError); FRIEND_TEST_ALL_PREFIXES(UpdateCheckerTest, UpdateCheckInvalidAp); FRIEND_TEST_ALL_PREFIXES(UpdateCheckerTest, UpdateCheckRequiresEncryptionError); FRIEND_TEST_ALL_PREFIXES(UpdateCheckerTest, UpdateCheckSuccess); FRIEND_TEST_ALL_PREFIXES(UpdateCheckerTest, UpdateCheckUpdateDisabled); // Describes an abstraction for implementing the behavior of a component and // the transition from one state to another. class State { public: using CallbackNextState = base::Callback next_state)>; State(Component* component, ComponentState state); virtual ~State(); // Handles the current state and initiates a transition to a new state. // The transition to the new state is non-blocking and it is completed // by the outer component, after the current state is fully handled. void Handle(CallbackNextState callback); ComponentState state() const { return state_; } bool IsFinal() const { return is_final_; } protected: // Initiates the transition to the new state. void TransitionState(std::unique_ptr new_state); Component& component() { return component_; } const Component& component() const { return component_; } CallbackNextState callback() const { return callback_; } base::ThreadChecker thread_checker_; const ComponentState state_; private: virtual void DoHandle() = 0; Component& component_; CallbackNextState callback_; bool is_final_ = false; }; class StateNew : public State { public: explicit StateNew(Component* component); ~StateNew() override; private: // State overrides. void DoHandle() override; DISALLOW_COPY_AND_ASSIGN(StateNew); }; class StateChecking : public State { public: explicit StateChecking(Component* component); ~StateChecking() override; private: // State overrides. void DoHandle() override; void UpdateCheckComplete(); DISALLOW_COPY_AND_ASSIGN(StateChecking); }; class StateUpdateError : public State { public: explicit StateUpdateError(Component* component); ~StateUpdateError() override; private: // State overrides. void DoHandle() override; DISALLOW_COPY_AND_ASSIGN(StateUpdateError); }; class StateCanUpdate : public State { public: explicit StateCanUpdate(Component* component); ~StateCanUpdate() override; private: // State overrides. void DoHandle() override; bool CanTryDiffUpdate() const; DISALLOW_COPY_AND_ASSIGN(StateCanUpdate); }; class StateUpToDate : public State { public: explicit StateUpToDate(Component* component); ~StateUpToDate() override; private: // State overrides. void DoHandle() override; DISALLOW_COPY_AND_ASSIGN(StateUpToDate); }; class StateDownloadingDiff : public State { public: explicit StateDownloadingDiff(Component* component); ~StateDownloadingDiff() override; private: // State overrides. void DoHandle() override; // Called when progress is being made downloading a CRX. The progress may // not monotonically increase due to how the CRX downloader switches between // different downloaders and fallback urls. void DownloadProgress(const std::string& id, const CrxDownloader::Result& download_result); void DownloadComplete(const std::string& id, const CrxDownloader::Result& download_result); // Downloads updates for one CRX id only. std::unique_ptr crx_downloader_; DISALLOW_COPY_AND_ASSIGN(StateDownloadingDiff); }; class StateDownloading : public State { public: explicit StateDownloading(Component* component); ~StateDownloading() override; private: // State overrides. void DoHandle() override; // Called when progress is being made downloading a CRX. The progress may // not monotonically increase due to how the CRX downloader switches between // different downloaders and fallback urls. void DownloadProgress(const std::string& id, const CrxDownloader::Result& download_result); void DownloadComplete(const std::string& id, const CrxDownloader::Result& download_result); // Downloads updates for one CRX id only. std::unique_ptr crx_downloader_; DISALLOW_COPY_AND_ASSIGN(StateDownloading); }; class StateUpdatingDiff : public State { public: explicit StateUpdatingDiff(Component* component); ~StateUpdatingDiff() override; private: // State overrides. void DoHandle() override; void InstallComplete(int error_category, int error_code, int extra_code1); DISALLOW_COPY_AND_ASSIGN(StateUpdatingDiff); }; class StateUpdating : public State { public: explicit StateUpdating(Component* component); ~StateUpdating() override; private: // State overrides. void DoHandle() override; void InstallComplete(int error_category, int error_code, int extra_code1); DISALLOW_COPY_AND_ASSIGN(StateUpdating); }; class StateUpdated : public State { public: explicit StateUpdated(Component* component); ~StateUpdated() override; private: // State overrides. void DoHandle() override; DISALLOW_COPY_AND_ASSIGN(StateUpdated); }; class StateUninstalled : public State { public: explicit StateUninstalled(Component* component); ~StateUninstalled() override; private: // State overrides. void DoHandle() override; DISALLOW_COPY_AND_ASSIGN(StateUninstalled); }; // Returns true is the update payload for this component can be downloaded // by a downloader which can do bandwidth throttling on the client side. bool CanDoBackgroundDownload() const; void AppendEvent(const std::string& event); // Changes the component state and notifies the caller of the |Handle| // function that the handling of this component state is complete. void ChangeState(std::unique_ptr next_state); // Notifies registered observers about changes in the state of the component. void NotifyObservers(Events event) const; base::ThreadChecker thread_checker_; const std::string id_; CrxComponent crx_component_; std::string status_; // Time when an update check for this CRX has happened. base::TimeTicks last_check_; // Time when the update of this CRX has begun. base::TimeTicks update_begin_; // A component can be made available for download from several urls. std::vector crx_urls_; std::vector crx_diffurls_; // The cryptographic hash values for the component payload. std::string hash_sha256_; std::string hashdiff_sha256_; // The from/to version and fingerprint values. base::Version previous_version_; base::Version next_version_; std::string previous_fp_; std::string next_fp_; // Contains the file name of the payload to run. std::string action_run_; // True if the update check response for this component includes an update. bool is_update_available_ = false; // True if the current update check cycle is on-demand. bool on_demand_ = false; // The error reported by the update checker. int update_check_error_ = 0; base::FilePath crx_path_; // The error information for full and differential updates. // The |error_category| contains a hint about which module in the component // updater generated the error. The |error_code| constains the error and // the |extra_code1| usually contains a system error, but it can contain // any extended information that is relevant to either the category or the // error itself. int error_category_ = 0; int error_code_ = 0; int extra_code1_ = 0; int diff_error_category_ = 0; int diff_error_code_ = 0; int diff_extra_code1_ = 0; // Contains the events which are serialized in the pings. std::vector events_; CallbackHandleComplete callback_handle_complete_; std::unique_ptr state_; const UpdateContext& update_context_; base::Closure update_check_complete_; DISALLOW_COPY_AND_ASSIGN(Component); }; using IdToComponentPtrMap = std::map>; } // namespace update_client #endif // COMPONENTS_UPDATE_CLIENT_COMPONENT_H_