Index: components/update_client/component.cc |
diff --git a/components/update_client/component.cc b/components/update_client/component.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f63b3c7e7a87aa9f610249e46b1ed412e1467f2a |
--- /dev/null |
+++ b/components/update_client/component.cc |
@@ -0,0 +1,701 @@ |
+// 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. |
+ |
+#include "components/update_client/component.h" |
+ |
+#include <algorithm> |
+#include <utility> |
+ |
+#include "base/bind.h" |
+#include "base/bind_helpers.h" |
+#include "base/files/file_util.h" |
+#include "base/location.h" |
+#include "base/logging.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/single_thread_task_runner.h" |
+#include "base/threading/thread_task_runner_handle.h" |
+#include "components/update_client/configurator.h" |
+#include "components/update_client/update_client.h" |
+#include "components/update_client/update_client_errors.h" |
+#include "components/update_client/update_engine.h" |
+#include "components/update_client/utils.h" |
+ |
+// The state machine representing how a CRX component changes during an update. |
+// |
+// |
+// on-demand on-demand |
+// +--------------------------> kNew <---------------+-------------+ |
+// | | | | |
+// | V | | |
+// | +---------------0----> kChecking -<-------+---|---<-----+ | |
+// | | | | | | | |
+// | | error V no | | | | |
+// kUpdateError <------------- [update?] ->---- kUpToDate kUpdated |
+// ^ | ^ |
+// | yes | | |
+// | V | |
+// | kCanUpdate | |
+// | | | |
+// | V no | |
+// | [differential update?]--->----+ | |
+// | | | | |
+// | yes | | | |
+// | V error | | |
+// | kDownloadingDiff --->---------+ | |
+// | | | | |
+// | | | | |
+// | V error | | |
+// | kUpdatingDiff --->--------+-----------+ success |
+// | | | |
+// | error V | |
+// +----------------------------------------- kDownloading | |
+// | | | |
+// | error V | |
+// +------------------------------------------ kUpdating ->----+ success |
+ |
+namespace update_client { |
+ |
+namespace { |
+ |
+using InstallOnBlockingTaskRunnerCompleteCallback = |
+ base::Callback<void(int error_category, int error_code, int extra_code1)>; |
+ |
+CrxInstaller::Result DoInstallOnBlockingTaskRunner( |
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, |
+ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, |
+ const base::FilePath& unpack_path, |
+ const std::string& fingerprint, |
+ const scoped_refptr<CrxInstaller>& installer, |
+ InstallOnBlockingTaskRunnerCompleteCallback callback) { |
+ DCHECK(blocking_task_runner->RunsTasksOnCurrentThread()); |
+ |
+ if (static_cast<int>(fingerprint.size()) != |
+ base::WriteFile( |
+ unpack_path.Append(FILE_PATH_LITERAL("manifest.fingerprint")), |
+ fingerprint.c_str(), base::checked_cast<int>(fingerprint.size()))) { |
+ return CrxInstaller::Result(InstallError::FINGERPRINT_WRITE_FAILED); |
+ } |
+ |
+ std::unique_ptr<base::DictionaryValue> manifest = ReadManifest(unpack_path); |
+ if (!manifest) |
+ return CrxInstaller::Result(InstallError::BAD_MANIFEST); |
+ |
+ return installer->Install(*manifest, unpack_path); |
+} |
+ |
+void InstallOnBlockingTaskRunner( |
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, |
+ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, |
+ const base::FilePath& unpack_path, |
+ const std::string& fingerprint, |
+ const scoped_refptr<CrxInstaller>& installer, |
+ InstallOnBlockingTaskRunnerCompleteCallback callback) { |
+ DCHECK(blocking_task_runner->RunsTasksOnCurrentThread()); |
+ |
+ const auto result = DoInstallOnBlockingTaskRunner( |
+ main_task_runner, blocking_task_runner, unpack_path, fingerprint, |
+ installer, callback); |
+ |
+ const ErrorCategory error_category = |
+ result.error ? ErrorCategory::kInstallError : ErrorCategory::kErrorNone; |
+ main_task_runner->PostTask( |
+ FROM_HERE, |
+ base::Bind(callback, static_cast<int>(error_category), |
+ static_cast<int>(result.error), result.extended_error)); |
+} |
+ |
+void UnpackCompleteOnBlockingTaskRunner( |
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, |
+ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, |
+ const base::FilePath& crx_path, |
+ const std::string& fingerprint, |
+ const scoped_refptr<CrxInstaller>& installer, |
+ InstallOnBlockingTaskRunnerCompleteCallback callback, |
+ const ComponentUnpacker::Result& result) { |
+ DCHECK(blocking_task_runner->RunsTasksOnCurrentThread()); |
+ |
+ update_client::DeleteFileAndEmptyParentDirectory(crx_path); |
+ |
+ if (result.error != UnpackerError::kNone) { |
+ main_task_runner->PostTask( |
+ FROM_HERE, |
+ base::Bind(callback, static_cast<int>(ErrorCategory::kUnpackError), |
+ static_cast<int>(result.error), result.extended_error)); |
+ return; |
+ } |
+ |
+ blocking_task_runner->PostTask( |
+ FROM_HERE, base::Bind(&InstallOnBlockingTaskRunner, main_task_runner, |
+ blocking_task_runner, result.unpack_path, |
+ fingerprint, installer, callback)); |
+} |
+ |
+void StartInstallOnBlockingTaskRunner( |
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, |
+ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, |
+ const std::vector<uint8_t>& pk_hash, |
+ const base::FilePath& crx_path, |
+ const std::string& fingerprint, |
+ const scoped_refptr<CrxInstaller>& installer, |
+ const scoped_refptr<OutOfProcessPatcher>& oop_patcher, |
+ InstallOnBlockingTaskRunnerCompleteCallback callback) { |
+ DCHECK(blocking_task_runner->RunsTasksOnCurrentThread()); |
+ |
+ auto unpacker = base::MakeShared<ComponentUnpacker>( |
+ pk_hash, crx_path, installer, oop_patcher, blocking_task_runner); |
+ |
+ unpacker->Unpack(base::Bind(&UnpackCompleteOnBlockingTaskRunner, |
+ main_task_runner, blocking_task_runner, crx_path, |
+ fingerprint, installer, callback)); |
+} |
+ |
+} // namespace |
+ |
+Component::Component(const UpdateContext& update_context, const std::string& id) |
+ : id_(id), |
+ state_(base::MakeUnique<StateNew>(this)), |
+ update_context_(update_context) {} |
+ |
+Component::~Component() {} |
+ |
+void Component::Handle(CallbackHandleComplete callback) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ DCHECK(state_); |
+ |
+ callback_handle_complete_ = callback; |
+ |
+ state_->Handle(base::Bind(&Component::ChangeState, base::Unretained(this))); |
+} |
+ |
+void Component::ChangeState(std::unique_ptr<State> next_state) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ if (next_state) |
+ state_ = std::move(next_state); |
+ |
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, |
+ callback_handle_complete_); |
+} |
+ |
+CrxUpdateItem Component::GetCrxUpdateItem() const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ CrxUpdateItem crx_update_item; |
+ crx_update_item.state = state_->state(); |
+ crx_update_item.id = id_; |
+ crx_update_item.component = crx_component_; |
+ crx_update_item.last_check = last_check_; |
+ crx_update_item.next_version = next_version_; |
+ crx_update_item.next_fp = next_fp_; |
+ |
+ return crx_update_item; |
+} |
+ |
+void Component::SetParseResult(const UpdateResponse::Result& result) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ DCHECK_EQ(0, update_check_error_); |
+ |
+ status_ = result.status; |
+ |
+ if (result.manifest.packages.empty()) |
+ return; |
+ |
+ next_version_ = base::Version(result.manifest.version); |
+ const auto& package = result.manifest.packages.front(); |
+ next_fp_ = package.fingerprint; |
+ |
+ // Resolve the urls by combining the base urls with the package names. |
+ for (const auto& crx_url : result.crx_urls) { |
+ const GURL url = crx_url.Resolve(package.name); |
+ if (url.is_valid()) |
+ crx_urls_.push_back(url); |
+ } |
+ for (const auto& crx_diffurl : result.crx_diffurls) { |
+ const GURL url = crx_diffurl.Resolve(package.namediff); |
+ if (url.is_valid()) |
+ crx_diffurls_.push_back(url); |
+ } |
+ |
+ hash_sha256_ = package.hash_sha256; |
+ hashdiff_sha256_ = package.hashdiff_sha256; |
+} |
+ |
+void Component::Uninstall(const base::Version& version, int reason) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ DCHECK_EQ(ComponentState::kNew, state()); |
+ |
+ previous_version_ = version; |
+ next_version_ = base::Version("0"); |
+ extra_code1_ = reason; |
+ |
+ state_ = base::MakeUnique<StateUninstalled>(this); |
+} |
+ |
+void Component::UpdateCheckComplete() const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ DCHECK_EQ(ComponentState::kChecking, state()); |
+ |
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, |
+ update_check_complete_); |
+} |
+ |
+bool Component::CanDoBackgroundDownload() const { |
+ // On demand component updates are always downloaded in foreground. |
+ return !on_demand_ && crx_component_.allows_background_download && |
+ update_context_.config->EnabledBackgroundDownloader(); |
+} |
+ |
+void Component::AppendDownloadMetrics( |
+ const std::vector<CrxDownloader::DownloadMetrics>& download_metrics) { |
+ download_metrics_.insert(download_metrics_.end(), download_metrics.begin(), |
+ download_metrics.end()); |
+} |
+ |
+void Component::NotifyObservers(UpdateClient::Observer::Events event) const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ update_context_.notify_observers_callback.Run(event, id_); |
+} |
+ |
+base::TimeDelta Component::GetUpdateDuration() const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ if (update_begin_.is_null()) |
+ return base::TimeDelta(); |
+ |
+ const base::TimeDelta update_cost(base::TimeTicks::Now() - update_begin_); |
+ DCHECK_GE(update_cost, base::TimeDelta()); |
+ const base::TimeDelta max_update_delay = |
+ base::TimeDelta::FromSeconds(update_context_.config->UpdateDelay()); |
+ return std::min(update_cost, max_update_delay); |
+} |
+ |
+Component::State::State(Component* component, ComponentState state) |
+ : state_(state), component_(*component) {} |
+ |
+Component::State::~State() {} |
+ |
+void Component::State::Handle(CallbackNextState callback) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ callback_ = callback; |
+ |
+ DCHECK(!is_final_); |
+ DoHandle(); |
+} |
+ |
+void Component::State::TransitionState(std::unique_ptr<State> next_state) { |
+ if (!next_state) |
+ is_final_ = true; |
+ |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(callback(), base::Passed(&next_state))); |
+} |
+ |
+Component::StateNew::StateNew(Component* component) |
+ : State(component, ComponentState::kNew) {} |
+ |
+Component::StateNew::~StateNew() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void Component::StateNew::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& component = State::component(); |
+ |
+ TransitionState(base::MakeUnique<StateChecking>(&component)); |
+} |
+ |
+Component::StateChecking::StateChecking(Component* component) |
+ : State(component, ComponentState::kChecking) {} |
+ |
+Component::StateChecking::~StateChecking() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+// Unlike how other states are handled, this function does not change the |
+// state right away. The state transition happens when the UpdateChecker |
+// calls Component::UpdateCheckComplete and |update_check_complete_| is invoked. |
+// This is an artifact of how multiple components must be checked for updates |
+// together but the state machine defines the transitions for one component |
+// at a time. |
+void Component::StateChecking::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& component = State::component(); |
+ |
+ component.last_check_ = base::TimeTicks::Now(); |
+ component.update_check_complete_ = base::Bind( |
+ &Component::StateChecking::UpdateCheckComplete, base::Unretained(this)); |
+ |
+ component.NotifyObservers(Events::COMPONENT_CHECKING_FOR_UPDATES); |
+} |
+ |
+void Component::StateChecking::UpdateCheckComplete() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ auto& component = State::component(); |
+ if (!component.update_check_error_) { |
+ if (component.status_ == "ok") { |
+ TransitionState(base::MakeUnique<StateCanUpdate>(&component)); |
+ return; |
+ } |
+ |
+ if (component.status_ == "noupdate") { |
+ TransitionState(base::MakeUnique<StateUpToDate>(&component)); |
+ return; |
+ } |
+ } |
+ |
+ TransitionState(base::MakeUnique<StateUpdateError>(&component)); |
+} |
+ |
+Component::StateUpdateError::StateUpdateError(Component* component) |
+ : State(component, ComponentState::kUpdateError) {} |
+ |
+Component::StateUpdateError::~StateUpdateError() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void Component::StateUpdateError::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& component = State::component(); |
+ TransitionState(nullptr); |
+ component.NotifyObservers(Events::COMPONENT_NOT_UPDATED); |
+} |
+ |
+Component::StateCanUpdate::StateCanUpdate(Component* component) |
+ : State(component, ComponentState::kCanUpdate) {} |
+ |
+Component::StateCanUpdate::~StateCanUpdate() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void Component::StateCanUpdate::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& component = State::component(); |
+ |
+ component.is_update_available_ = true; |
+ component.NotifyObservers(Events::COMPONENT_UPDATE_FOUND); |
+ |
+ if (component.crx_component_.supports_group_policy_enable_component_updates && |
+ !component.update_context_.enabled_component_updates) { |
+ component.error_category_ = static_cast<int>(ErrorCategory::kServiceError); |
+ component.error_code_ = static_cast<int>(ServiceError::UPDATE_DISABLED); |
+ component.extra_code1_ = 0; |
+ TransitionState(base::MakeUnique<StateUpdateError>(&component)); |
+ return; |
+ } |
+ |
+ // Start computing the cost of the this update from here on. |
+ component.update_begin_ = base::TimeTicks::Now(); |
+ |
+ if (CanTryDiffUpdate()) |
+ TransitionState(base::MakeUnique<StateDownloadingDiff>(&component)); |
+ else |
+ TransitionState(base::MakeUnique<StateDownloading>(&component)); |
+} |
+ |
+// Returns true if a differential update is available, it has not failed yet, |
+// and the configuration allows this update. |
+bool Component::StateCanUpdate::CanTryDiffUpdate() const { |
+ const auto& component = Component::State::component(); |
+ return HasDiffUpdate(component) && !component.diff_error_code_ && |
+ component.update_context_.config->EnabledDeltas(); |
+} |
+ |
+Component::StateUpToDate::StateUpToDate(Component* component) |
+ : State(component, ComponentState::kUpToDate) {} |
+ |
+Component::StateUpToDate::~StateUpToDate() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void Component::StateUpToDate::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& component = State::component(); |
+ |
+ TransitionState(nullptr); |
+ component.NotifyObservers(Events::COMPONENT_NOT_UPDATED); |
+} |
+ |
+Component::StateDownloadingDiff::StateDownloadingDiff(Component* component) |
+ : State(component, ComponentState::kDownloadingDiff) {} |
+ |
+Component::StateDownloadingDiff::~StateDownloadingDiff() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void Component::StateDownloadingDiff::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ const auto& component = Component::State::component(); |
+ const auto& update_context = component.update_context_; |
+ |
+ crx_downloader_ = update_context.crx_downloader_factory( |
+ component.CanDoBackgroundDownload(), |
+ update_context.config->RequestContext(), |
+ update_context.blocking_task_runner); |
+ |
+ const auto& id = component.id_; |
+ crx_downloader_->set_progress_callback( |
+ base::Bind(&Component::StateDownloadingDiff::DownloadProgress, |
+ base::Unretained(this), id)); |
+ crx_downloader_->StartDownload( |
+ component.crx_diffurls_, component.hashdiff_sha256_, |
+ base::Bind(&Component::StateDownloadingDiff::DownloadComplete, |
+ base::Unretained(this), id)); |
+ |
+ component.NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING); |
+} |
+ |
+// 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 Component::StateDownloadingDiff::DownloadProgress( |
+ const std::string& id, |
+ const CrxDownloader::Result& download_result) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ component().NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING); |
+} |
+ |
+void Component::StateDownloadingDiff::DownloadComplete( |
+ const std::string& id, |
+ const CrxDownloader::Result& download_result) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& component = Component::State::component(); |
+ |
+ component.AppendDownloadMetrics(crx_downloader_->download_metrics()); |
+ |
+ crx_downloader_.reset(); |
+ |
+ if (download_result.error) { |
+ component.diff_error_category_ = |
+ static_cast<int>(ErrorCategory::kNetworkError); |
+ component.diff_error_code_ = download_result.error; |
+ |
+ TransitionState(base::MakeUnique<StateDownloading>(&component)); |
+ return; |
+ } |
+ |
+ component.crx_path_ = download_result.response; |
+ |
+ TransitionState(base::MakeUnique<StateUpdatingDiff>(&component)); |
+} |
+ |
+Component::StateDownloading::StateDownloading(Component* component) |
+ : State(component, ComponentState::kDownloading) {} |
+ |
+Component::StateDownloading::~StateDownloading() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void Component::StateDownloading::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ const auto& component = Component::State::component(); |
+ const auto& update_context = component.update_context_; |
+ |
+ crx_downloader_ = update_context.crx_downloader_factory( |
+ component.CanDoBackgroundDownload(), |
+ update_context.config->RequestContext(), |
+ update_context.blocking_task_runner); |
+ |
+ const auto& id = component.id_; |
+ crx_downloader_->set_progress_callback( |
+ base::Bind(&Component::StateDownloading::DownloadProgress, |
+ base::Unretained(this), id)); |
+ crx_downloader_->StartDownload( |
+ component.crx_urls_, component.hash_sha256_, |
+ base::Bind(&Component::StateDownloading::DownloadComplete, |
+ base::Unretained(this), id)); |
+ |
+ component.NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING); |
+} |
+ |
+// 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 Component::StateDownloading::DownloadProgress( |
+ const std::string& id, |
+ const CrxDownloader::Result& download_result) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ component().NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING); |
+} |
+ |
+void Component::StateDownloading::DownloadComplete( |
+ const std::string& id, |
+ const CrxDownloader::Result& download_result) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& component = Component::State::component(); |
+ |
+ component.AppendDownloadMetrics(crx_downloader_->download_metrics()); |
+ |
+ crx_downloader_.reset(); |
+ |
+ if (download_result.error) { |
+ component.error_category_ = static_cast<int>(ErrorCategory::kNetworkError); |
+ component.error_code_ = download_result.error; |
+ |
+ TransitionState(base::MakeUnique<StateUpdateError>(&component)); |
+ return; |
+ } |
+ |
+ component.crx_path_ = download_result.response; |
+ |
+ TransitionState(base::MakeUnique<StateUpdating>(&component)); |
+} |
+ |
+Component::StateUpdatingDiff::StateUpdatingDiff(Component* component) |
+ : State(component, ComponentState::kUpdatingDiff) {} |
+ |
+Component::StateUpdatingDiff::~StateUpdatingDiff() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void Component::StateUpdatingDiff::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ const auto& component = Component::State::component(); |
+ const auto& update_context = component.update_context_; |
+ |
+ component.NotifyObservers(Events::COMPONENT_UPDATE_READY); |
+ |
+ update_context.blocking_task_runner->PostTask( |
+ FROM_HERE, |
+ base::Bind(&update_client::StartInstallOnBlockingTaskRunner, |
+ base::ThreadTaskRunnerHandle::Get(), |
+ update_context.blocking_task_runner, |
+ component.crx_component_.pk_hash, component.crx_path_, |
+ component.next_fp_, component.crx_component_.installer, |
+ update_context.config->CreateOutOfProcessPatcher(), |
+ base::Bind(&Component::StateUpdatingDiff::InstallComplete, |
+ base::Unretained(this)))); |
+} |
+ |
+void Component::StateUpdatingDiff::InstallComplete(int error_category, |
+ int error_code, |
+ int extra_code1) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& component = Component::State::component(); |
+ |
+ component.diff_error_category_ = error_category; |
+ component.diff_error_code_ = error_code; |
+ component.diff_extra_code1_ = extra_code1; |
+ |
+ if (component.diff_error_code_ != 0) { |
+ TransitionState(base::MakeUnique<StateDownloading>(&component)); |
+ return; |
+ } |
+ |
+ DCHECK_EQ(static_cast<int>(ErrorCategory::kErrorNone), |
+ component.diff_error_category_); |
+ DCHECK_EQ(0, component.diff_error_code_); |
+ DCHECK_EQ(0, component.diff_extra_code1_); |
+ |
+ DCHECK_EQ(static_cast<int>(ErrorCategory::kErrorNone), |
+ component.error_category_); |
+ DCHECK_EQ(0, component.error_code_); |
+ DCHECK_EQ(0, component.extra_code1_); |
+ |
+ TransitionState(base::MakeUnique<StateUpdated>(&component)); |
+} |
+ |
+Component::StateUpdating::StateUpdating(Component* component) |
+ : State(component, ComponentState::kUpdating), |
+ main_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} |
+ |
+Component::StateUpdating::~StateUpdating() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void Component::StateUpdating::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ const auto& component = Component::State::component(); |
+ const auto& update_context = component.update_context_; |
+ |
+ component.NotifyObservers(Events::COMPONENT_UPDATE_READY); |
+ |
+ update_context.blocking_task_runner->PostTask( |
+ FROM_HERE, |
+ base::Bind(&update_client::StartInstallOnBlockingTaskRunner, |
+ base::ThreadTaskRunnerHandle::Get(), |
+ update_context.blocking_task_runner, |
+ component.crx_component_.pk_hash, component.crx_path_, |
+ component.next_fp_, component.crx_component_.installer, |
+ update_context.config->CreateOutOfProcessPatcher(), |
+ base::Bind(&Component::StateUpdating::InstallComplete, |
+ base::Unretained(this)))); |
+} |
+ |
+void Component::StateUpdating::InstallComplete(int error_category, |
+ int error_code, |
+ int extra_code1) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& component = Component::State::component(); |
+ |
+ component.error_category_ = error_category; |
+ component.error_code_ = error_code; |
+ component.extra_code1_ = extra_code1; |
+ |
+ if (component.error_code_ != 0) { |
+ TransitionState(base::MakeUnique<StateUpdateError>(&component)); |
+ return; |
+ } |
+ |
+ DCHECK_EQ(static_cast<int>(ErrorCategory::kErrorNone), |
+ component.error_category_); |
+ DCHECK_EQ(0, component.error_code_); |
+ DCHECK_EQ(0, component.extra_code1_); |
+ |
+ TransitionState(base::MakeUnique<StateUpdated>(&component)); |
+} |
+ |
+Component::StateUpdated::StateUpdated(Component* component) |
+ : State(component, ComponentState::kUpdated) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+Component::StateUpdated::~StateUpdated() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void Component::StateUpdated::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& component = State::component(); |
+ component.crx_component_.version = component.next_version_; |
+ component.crx_component_.fingerprint = component.next_fp_; |
+ |
+ TransitionState(nullptr); |
+ component.NotifyObservers(Events::COMPONENT_UPDATED); |
+} |
+ |
+Component::StateUninstalled::StateUninstalled(Component* component) |
+ : State(component, ComponentState::kUninstalled) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+Component::StateUninstalled::~StateUninstalled() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void Component::StateUninstalled::DoHandle() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ TransitionState(nullptr); |
+} |
+ |
+} // namespace update_client |