Refactor the UpdateEngine and its actions in the component updater.

[email protected]
BUG=687231

Review-Url: https://codereview.chromium.org/2835803002
Cr-Commit-Position: refs/heads/master@{#467535}
diff --git a/components/update_client/component.h b/components/update_client/component.h
new file mode 100644
index 0000000..c5709c0a
--- /dev/null
+++ b/components/update_client/component.h
@@ -0,0 +1,437 @@
+// 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/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "base/version.h"
+#include "components/update_client/component_unpacker.h"
+#include "components/update_client/crx_downloader.h"
+#include "components/update_client/update_client.h"
+#include "components/update_client/update_response.h"
+#include "url/gurl.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+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<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| is invoked.
+  void Handle(CallbackHandleComplete callback);
+
+  CrxUpdateItem GetCrxUpdateItem() const;
+
+  // Called by the UpdateChecker to set the update response for this component.
+  void SetParseResult(const UpdateResponse::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_; }
+
+  // Returns true if a ping must be sent back to the server. As a general rule,
+  // a ping is sent only for server responses containing instructions to update.
+  bool CanPing() const {
+    return IsUpdateAvailable() || state() == ComponentState::kUninstalled;
+  }
+
+  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<CrxDownloader::DownloadMetrics>& download_metrics() const {
+    return download_metrics_;
+  }
+
+  const std::vector<GURL>& 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, 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<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);
+
+    ComponentState state() const { return state_; }
+
+    bool IsFinal() const { return is_final_; }
+
+   protected:
+    // Initiates the transition to the new state.
+    void TransitionState(std::unique_ptr<State> 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<CrxDownloader> 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<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(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);
+
+    // Posts replies back to the main thread.
+    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+
+    // Unpacks one CRX.
+    scoped_refptr<ComponentUnpacker> unpacker_;
+
+    base::FilePath unpack_path_;
+
+    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 AppendDownloadMetrics(
+      const std::vector<CrxDownloader::DownloadMetrics>& download_metrics);
+
+  // 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;
+
+  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<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_;
+
+  // 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;
+
+  std::vector<CrxDownloader::DownloadMetrics> download_metrics_;
+
+  CallbackHandleComplete callback_handle_complete_;
+  std::unique_ptr<State> state_;
+  const UpdateContext& update_context_;
+
+  base::Closure update_check_complete_;
+
+  DISALLOW_COPY_AND_ASSIGN(Component);
+};
+
+using IdToComponentPtrMap = std::map<std::string, std::unique_ptr<Component>>;
+
+}  // namespace update_client
+
+#endif  // COMPONENTS_UPDATE_CLIENT_COMPONENT_H_