Index: components/update_client/update_engine.cc |
diff --git a/components/update_client/update_engine.cc b/components/update_client/update_engine.cc |
index b127befe91b3906c8b6277a1b9ad86ceb8886f34..afef9097097c21598b51bcd0e655cda99f66ee3e 100644 |
--- a/components/update_client/update_engine.cc |
+++ b/components/update_client/update_engine.cc |
@@ -4,19 +4,23 @@ |
#include "components/update_client/update_engine.h" |
+#include <utility> |
+ |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
#include "base/location.h" |
+#include "base/logging.h" |
+#include "base/memory/ptr_util.h" |
#include "base/stl_util.h" |
#include "base/threading/thread_task_runner_handle.h" |
-#include "base/time/time.h" |
#include "components/prefs/pref_service.h" |
-#include "components/update_client/action_update_check.h" |
+#include "components/update_client/component.h" |
#include "components/update_client/configurator.h" |
#include "components/update_client/crx_update_item.h" |
#include "components/update_client/persisted_data.h" |
#include "components/update_client/update_checker.h" |
#include "components/update_client/update_client_errors.h" |
+#include "components/update_client/utils.h" |
namespace update_client { |
@@ -27,9 +31,7 @@ UpdateContext::UpdateContext( |
const UpdateClient::CrxDataCallback& crx_data_callback, |
const UpdateEngine::NotifyObserversCallback& notify_observers_callback, |
const UpdateEngine::Callback& callback, |
- UpdateChecker::Factory update_checker_factory, |
- CrxDownloader::Factory crx_downloader_factory, |
- PingManager* ping_manager) |
+ CrxDownloader::Factory crx_downloader_factory) |
: config(config), |
is_foreground(is_foreground), |
enabled_component_updates(config->EnabledComponentUpdates()), |
@@ -37,12 +39,12 @@ UpdateContext::UpdateContext( |
crx_data_callback(crx_data_callback), |
notify_observers_callback(notify_observers_callback), |
callback(callback), |
- main_task_runner(base::ThreadTaskRunnerHandle::Get()), |
blocking_task_runner(config->GetSequencedTaskRunner()), |
- update_checker_factory(update_checker_factory), |
- crx_downloader_factory(crx_downloader_factory), |
- ping_manager(ping_manager), |
- retry_after_sec(0) {} |
+ crx_downloader_factory(crx_downloader_factory) { |
+ for (const auto& id : ids) |
+ components.insert( |
+ std::make_pair(id, base::MakeUnique<Component>(*this, id))); |
+} |
UpdateContext::~UpdateContext() {} |
@@ -63,20 +65,6 @@ UpdateEngine::~UpdateEngine() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
} |
-bool UpdateEngine::GetUpdateState(const std::string& id, |
- CrxUpdateItem* update_item) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- for (const auto* context : update_contexts_) { |
- const auto& update_items = context->update_items; |
- const auto it = update_items.find(id); |
- if (it != update_items.end()) { |
- *update_item = *it->second.get(); |
- return true; |
- } |
- } |
- return false; |
-} |
- |
void UpdateEngine::Update( |
bool is_foreground, |
const std::vector<std::string>& ids, |
@@ -90,29 +78,98 @@ void UpdateEngine::Update( |
return; |
} |
- std::unique_ptr<UpdateContext> update_context(new UpdateContext( |
+ const auto result = update_contexts_.insert(base::MakeUnique<UpdateContext>( |
config_, is_foreground, ids, crx_data_callback, |
- notify_observers_callback_, callback, update_checker_factory_, |
- crx_downloader_factory_, ping_manager_)); |
+ notify_observers_callback_, callback, crx_downloader_factory_)); |
+ |
+ DCHECK(result.second); |
- std::unique_ptr<ActionUpdateCheck> update_check_action(new ActionUpdateCheck( |
- (*update_context->update_checker_factory)(config_, metadata_.get()), |
- config_->GetBrowserVersion(), config_->ExtraRequestParams())); |
+ const auto& it = result.first; |
+ const auto& update_context = *it; |
+ DCHECK(update_context); |
- update_context->current_action = std::move(update_check_action); |
- update_contexts_.insert(update_context.get()); |
+ // Calls out to get the corresponding CrxComponent data for the CRXs in this |
+ // update context. |
+ DCHECK_EQ(ids.size(), update_context->ids.size()); |
+ DCHECK_EQ(update_context->ids.size(), update_context->components.size()); |
+ std::vector<CrxComponent> crx_components; |
+ update_context->crx_data_callback.Run(update_context->ids, &crx_components); |
+ DCHECK_EQ(update_context->ids.size(), crx_components.size()); |
- update_context->current_action->Run( |
- update_context.get(), |
- base::Bind(&UpdateEngine::UpdateComplete, base::Unretained(this), |
- update_context.get())); |
+ for (size_t i = 0; i != update_context->ids.size(); ++i) { |
+ const auto& id = update_context->ids[i]; |
+ const auto& crx_component = crx_components[i]; |
- ignore_result(update_context.release()); |
+ DCHECK_EQ(id, GetCrxComponentID(crx_component)); |
+ DCHECK_EQ(1u, update_context->components.count(id)); |
+ DCHECK(update_context->components.at(id)); |
+ |
+ auto& component = *update_context->components.at(id); |
+ component.set_on_demand(update_context->is_foreground); |
+ component.set_crx_component(crx_component); |
+ component.set_previous_version(crx_component.version); |
+ component.set_previous_fp(crx_component.fingerprint); |
+ |
+ // Handle |kNew| state. This will transition the components to |kChecking|. |
+ component.Handle(base::Bind(&UpdateEngine::ComponentCheckingForUpdatesStart, |
+ base::Unretained(this), it, |
+ base::ConstRef(component))); |
+ } |
+} |
+ |
+void UpdateEngine::ComponentCheckingForUpdatesStart( |
+ const UpdateContextIterator& it, |
+ const Component& component) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ const auto& update_context = *it; |
+ DCHECK(update_context); |
+ |
+ const auto id = component.id(); |
+ DCHECK_EQ(1u, update_context->components.count(id)); |
+ DCHECK(update_context->components.at(id)); |
+ |
+ // Handle |kChecking| state. |
+ auto& mutable_component = *update_context->components.at(id); |
+ mutable_component.Handle(base::Bind( |
+ &UpdateEngine::ComponentCheckingForUpdatesComplete, |
+ base::Unretained(this), it, base::ConstRef(mutable_component))); |
+ |
+ ++update_context->num_components_ready_to_check; |
+ if (update_context->num_components_ready_to_check < |
+ update_context->ids.size()) { |
+ return; |
+ } |
+ |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&UpdateEngine::DoUpdateCheck, base::Unretained(this), it)); |
} |
-void UpdateEngine::UpdateComplete(UpdateContext* update_context, Error error) { |
+void UpdateEngine::DoUpdateCheck(const UpdateContextIterator& it) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- DCHECK(update_contexts_.find(update_context) != update_contexts_.end()); |
+ |
+ auto& update_context = *it; |
+ DCHECK(update_context); |
+ |
+ update_context->update_checker = |
+ update_checker_factory_(config_, metadata_.get()); |
+ |
+ update_context->update_checker->CheckForUpdates( |
+ update_context->ids, update_context->components, |
+ config_->ExtraRequestParams(), update_context->enabled_component_updates, |
+ base::Bind(&UpdateEngine::UpdateCheckDone, base::Unretained(this), it)); |
+} |
+ |
+void UpdateEngine::UpdateCheckDone(const UpdateContextIterator& it, |
+ int error, |
+ int retry_after_sec) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& update_context = *it; |
+ DCHECK(update_context); |
+ |
+ update_context->retry_after_sec = retry_after_sec; |
const int throttle_sec(update_context->retry_after_sec); |
DCHECK_LE(throttle_sec, 24 * 60 * 60); |
@@ -120,22 +177,161 @@ void UpdateEngine::UpdateComplete(UpdateContext* update_context, Error error) { |
// Only positive values for throttle_sec are effective. 0 means that no |
// throttling occurs and has the effect of resetting the member. |
// Negative values are not trusted and are ignored. |
- if (throttle_sec >= 0) |
+ if (throttle_sec >= 0) { |
throttle_updates_until_ = |
- throttle_sec |
- ? base::TimeTicks::Now() + |
- base::TimeDelta::FromSeconds(throttle_sec) |
- : base::TimeTicks(); |
+ throttle_sec ? base::TimeTicks::Now() + |
+ base::TimeDelta::FromSeconds(throttle_sec) |
+ : base::TimeTicks(); |
+ } |
+ |
+ update_context->update_check_error = error; |
- auto callback = update_context->callback; |
+ for (const auto& id : update_context->ids) { |
+ DCHECK_EQ(1u, update_context->components.count(id)); |
+ DCHECK(update_context->components.at(id)); |
+ |
+ auto& component = *update_context->components.at(id); |
+ component.UpdateCheckComplete(); |
+ } |
+} |
+ |
+void UpdateEngine::ComponentCheckingForUpdatesComplete( |
+ const UpdateContextIterator& it, |
+ const Component& component) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ const auto& update_context = *it; |
+ DCHECK(update_context); |
+ |
+ ++update_context->num_components_checked; |
+ if (update_context->num_components_checked < update_context->ids.size()) { |
+ return; |
+ } |
+ |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(&UpdateEngine::UpdateCheckComplete, |
+ base::Unretained(this), it)); |
+} |
+ |
+void UpdateEngine::UpdateCheckComplete(const UpdateContextIterator& it) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ const auto& update_context = *it; |
+ DCHECK(update_context); |
+ |
+ if (update_context->update_check_error) { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&UpdateEngine::UpdateComplete, base::Unretained(this), it, |
+ Error::UPDATE_CHECK_ERROR)); |
+ return; |
+ } |
- update_contexts_.erase(update_context); |
- delete update_context; |
+ for (const auto& id : update_context->ids) |
+ update_context->component_queue.push(id); |
- callback.Run(error); |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it)); |
+} |
+ |
+void UpdateEngine::HandleComponent(const UpdateContextIterator& it) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& update_context = *it; |
+ DCHECK(update_context); |
+ |
+ auto& queue = update_context->component_queue; |
+ |
+ if (queue.empty()) { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(&UpdateEngine::UpdateComplete, |
+ base::Unretained(this), it, Error::NONE)); |
+ return; |
+ } |
+ |
+ const auto& id = queue.front(); |
+ DCHECK_EQ(1u, update_context->components.count(id)); |
+ const auto& component = update_context->components.at(id); |
+ DCHECK(component); |
+ |
+ auto& next_update_delay = (*it)->next_update_delay; |
+ if (!next_update_delay.is_zero() && component->IsUpdateAvailable()) { |
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it), |
+ next_update_delay); |
+ |
+ next_update_delay = base::TimeDelta(); |
+ |
+ notify_observers_callback_.Run( |
+ UpdateClient::Observer::Events::COMPONENT_WAIT, id); |
+ return; |
+ } |
+ |
+ component->Handle(base::Bind(&UpdateEngine::HandleComponentComplete, |
+ base::Unretained(this), it)); |
+} |
+ |
+void UpdateEngine::HandleComponentComplete(const UpdateContextIterator& it) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& update_context = *it; |
+ DCHECK(update_context); |
+ |
+ auto& queue = update_context->component_queue; |
+ DCHECK(!queue.empty()); |
+ |
+ const auto& id = queue.front(); |
+ DCHECK_EQ(1u, update_context->components.count(id)); |
+ const auto& component = update_context->components.at(id); |
+ DCHECK(component); |
+ |
+ if (component->IsHandled()) { |
+ (*it)->next_update_delay = component->GetUpdateDuration(); |
+ |
+ // Only ping when the server response included an update for this component. |
+ if (component->CanPing()) { |
+ ping_manager_->SendPing(*component); |
+ } |
+ |
+ queue.pop(); |
+ } |
+ |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it)); |
+} |
+ |
+void UpdateEngine::UpdateComplete(const UpdateContextIterator& it, |
+ Error error) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ auto& update_context = *it; |
+ DCHECK(update_context); |
+ |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(update_context->callback, error)); |
+ |
+ update_contexts_.erase(it); |
+} |
+ |
+bool UpdateEngine::GetUpdateState(const std::string& id, |
+ CrxUpdateItem* update_item) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ for (const auto& context : update_contexts_) { |
+ const auto it = context->components.find(id); |
+ if (it != context->components.end()) { |
+ *update_item = it->second->GetCrxUpdateItem(); |
+ return true; |
+ } |
+ } |
+ return false; |
} |
bool UpdateEngine::IsThrottled(bool is_foreground) const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
if (is_foreground || throttle_updates_until_.is_null()) |
return false; |
@@ -147,4 +343,33 @@ bool UpdateEngine::IsThrottled(bool is_foreground) const { |
now < throttle_updates_until_; |
} |
+void UpdateEngine::SendUninstallPing(const std::string& id, |
+ const base::Version& version, |
+ int reason, |
+ const Callback& callback) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ const auto result = update_contexts_.insert(base::MakeUnique<UpdateContext>( |
+ config_, false, std::vector<std::string>{id}, |
+ UpdateClient::CrxDataCallback(), UpdateEngine::NotifyObserversCallback(), |
+ callback, nullptr)); |
+ |
+ DCHECK(result.second); |
+ |
+ const auto& it = result.first; |
+ const auto& update_context = *it; |
+ DCHECK(update_context); |
+ DCHECK_EQ(1u, update_context->ids.size()); |
+ DCHECK_EQ(1u, update_context->components.count(id)); |
+ const auto& component = update_context->components.at(id); |
+ |
+ component->Uninstall(version, reason); |
+ |
+ update_context->component_queue.push(id); |
+ |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it)); |
+} |
+ |
} // namespace update_client |