| // 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 <map> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #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/optional.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" |
| |
| #if defined(STARBOARD) |
| #include "starboard/extension/installation_manager.h" |
| #endif |
| |
| namespace base { |
| class Value; |
| } // namespace base |
| |
| namespace update_client { |
| |
| class ActionRunner; |
| class Configurator; |
| 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::OnceCallback<void()>; |
| |
| 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_handle_complete_| is invoked. |
| void Handle(CallbackHandleComplete callback_handle_complete); |
| |
| #if defined(STARBOARD) |
| // Stops update progress for the component and may clean resources used in its |
| // current state. |
| void Cancel(); |
| #endif |
| |
| CrxUpdateItem GetCrxUpdateItem() const; |
| |
| // 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 SetUpdateCheckResult( |
| const base::Optional<ProtocolParser::Result>& result, |
| ErrorCategory error_category, |
| int error); |
| |
| // Returns true if the component has reached a final state and no further |
| // handling and state transitions are possible. |
| bool IsHandled() const { return is_handled_; } |
| |
| // 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 base::Optional<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; } |
| |
| bool is_foreground() const; |
| |
| const std::vector<GURL>& crx_diffurls() const { return crx_diffurls_; } |
| |
| bool diff_update_failed() const { return !!diff_error_code_; } |
| |
| ErrorCategory error_category() const { return error_category_; } |
| int error_code() const { return error_code_; } |
| int extra_code1() const { return extra_code1_; } |
| ErrorCategory 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_; } |
| |
| std::string action_run() const { return action_run_; } |
| |
| scoped_refptr<Configurator> config() const; |
| |
| std::string session_id() const; |
| |
| const std::vector<base::Value>& events() const { return events_; } |
| |
| // Returns a clone of the component events. |
| std::vector<base::Value> GetEvents() const; |
| |
| private: |
| #if defined(STARBOARD) |
| bool is_cancelled_ = false; |
| #endif |
| friend class MockPingManagerImpl; |
| 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::OnceCallback<void(std::unique_ptr<State> 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); |
| |
| #if defined(STARBOARD) |
| // Stops update progress and may clean resources used in the current state. |
| virtual void Cancel(); |
| #endif |
| |
| ComponentState state() const { return state_; } |
| |
| #if defined(STARBOARD) |
| std::string state_name() { |
| switch (state_) { |
| case ComponentState::kNew: |
| return "New"; |
| case ComponentState::kChecking: |
| return "Checking"; |
| case ComponentState::kCanUpdate: |
| return "CanUpdate"; |
| case ComponentState::kDownloadingDiff: |
| return "DownloadingDiff"; |
| case ComponentState::kDownloading: |
| return "Downloaded"; |
| case ComponentState::kUpdatingDiff: |
| return "UpdatingDiff"; |
| case ComponentState::kUpdating: |
| return "Updating"; |
| case ComponentState::kUpdated: |
| return "Updated"; |
| case ComponentState::kUpToDate: |
| return "UpToDate"; |
| case ComponentState::kUpdateError: |
| return "UpdateError"; |
| case ComponentState::kUninstalled: |
| return "Uninstalled"; |
| case ComponentState::kRun: |
| return "Run"; |
| case ComponentState::kLastStatus: |
| return "LastStatus"; |
| default: |
| return "Unknown"; |
| } |
| } |
| #endif |
| |
| protected: |
| // Initiates the transition to the new state. |
| void TransitionState(std::unique_ptr<State> new_state); |
| |
| // Makes the current state a final state where no other state transition |
| // can further occur. |
| void EndState(); |
| |
| Component& component() { return component_; } |
| const Component& component() const { return component_; } |
| |
| base::ThreadChecker thread_checker_; |
| |
| const ComponentState state_; |
| |
| private: |
| virtual void DoHandle() = 0; |
| |
| Component& component_; |
| CallbackNextState callback_next_state_; |
| }; |
| |
| 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; |
| #if defined(STARBOARD) |
| void Cancel() override; |
| #endif |
| |
| private: |
| // State overrides. |
| void DoHandle() override; |
| |
| // Called when progress is being made downloading a CRX. Can be called |
| // multiple times due to how the CRX downloader switches between |
| // different downloaders and fallback urls. |
| void DownloadProgress(const std::string& id); |
| |
| void DownloadComplete(const std::string& id, |
| const CrxDownloader::Result& download_result); |
| |
| // Downloads updates for one CRX id only. |
| std::unique_ptr<CrxDownloader> crx_downloader_; |
| |
| DISALLOW_COPY_AND_ASSIGN(StateDownloadingDiff); |
| }; |
| |
| class StateDownloading : public State { |
| public: |
| explicit StateDownloading(Component* component); |
| ~StateDownloading() override; |
| #if defined(STARBOARD) |
| void Cancel() override; |
| #endif |
| |
| private: |
| // State overrides. |
| void DoHandle() override; |
| |
| // Called when progress is being made downloading a CRX. Can be called |
| // multiple times due to how the CRX downloader switches between |
| // different downloaders and fallback urls. |
| void DownloadProgress(const std::string& id); |
| |
| void DownloadComplete(const std::string& id, |
| const CrxDownloader::Result& download_result); |
| |
| // Downloads updates for one CRX id only. |
| std::unique_ptr<CrxDownloader> 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(ErrorCategory 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(ErrorCategory 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); |
| }; |
| |
| class StateRun : public State { |
| public: |
| explicit StateRun(Component* component); |
| ~StateRun() override; |
| |
| private: |
| // State overrides. |
| void DoHandle() override; |
| |
| void ActionRunComplete(bool succeeded, int error_code, int extra_code1); |
| |
| // Runs the action referred by the |action_run_| member of the Component |
| // class. |
| std::unique_ptr<ActionRunner> action_runner_; |
| |
| DISALLOW_COPY_AND_ASSIGN(StateRun); |
| }; |
| |
| // 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(base::Value 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<State> next_state); |
| |
| // Notifies registered observers about changes in the state of the component. |
| void NotifyObservers(Events event) const; |
| |
| void SetParseResult(const ProtocolParser::Result& result); |
| |
| // These functions return a specific event. Each data member of the event is |
| // represented as a key-value pair in a dictionary value. |
| base::Value MakeEventUpdateComplete() const; |
| base::Value MakeEventDownloadMetrics( |
| const CrxDownloader::DownloadMetrics& download_metrics) const; |
| base::Value MakeEventUninstalled() const; |
| base::Value MakeEventActionRun(bool succeeded, |
| int error_code, |
| int extra_code1) const; |
| |
| base::ThreadChecker thread_checker_; |
| |
| const std::string id_; |
| base::Optional<CrxComponent> crx_component_; |
| |
| // The status of the updatecheck response. |
| 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<GURL> crx_urls_; |
| std::vector<GURL> 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. This member is set by |
| // the update response parser, when the update response includes a run action. |
| std::string action_run_; |
| |
| // True if the update check response for this component includes an update. |
| bool is_update_available_ = false; |
| |
| // The error reported by the update checker. |
| int update_check_error_ = 0; |
| |
| base::FilePath crx_path_; |
| |
| #if defined(STARBOARD) |
| int installation_index_ = IM_EXT_INVALID_INDEX; |
| #endif |
| |
| // 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. |
| ErrorCategory error_category_ = ErrorCategory::kNone; |
| int error_code_ = 0; |
| int extra_code1_ = 0; |
| ErrorCategory diff_error_category_ = ErrorCategory::kNone; |
| int diff_error_code_ = 0; |
| int diff_extra_code1_ = 0; |
| |
| // Contains the events which are therefore serialized in the requests. |
| std::vector<base::Value> events_; |
| |
| CallbackHandleComplete callback_handle_complete_; |
| std::unique_ptr<State> state_; |
| const UpdateContext& update_context_; |
| |
| base::OnceClosure update_check_complete_; |
| |
| ComponentState previous_state_ = ComponentState::kLastStatus; |
| |
| // True if this component has reached a final state because all its states |
| // have been handled. |
| bool is_handled_ = false; |
| |
| DISALLOW_COPY_AND_ASSIGN(Component); |
| }; |
| |
| using IdToComponentPtrMap = std::map<std::string, std::unique_ptr<Component>>; |
| |
| } // namespace update_client |
| |
| #endif // COMPONENTS_UPDATE_CLIENT_COMPONENT_H_ |