blob: c0bf0ae8c625f1e5f293dae729bae1df7866fce6 [file] [log] [blame]
// Copyright 2015 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/update_engine.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.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/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"
namespace update_client {
UpdateContext::UpdateContext(
const scoped_refptr<Configurator>& config,
bool is_foreground,
const std::vector<std::string>& ids,
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)
: config(config),
is_foreground(is_foreground),
enabled_component_updates(config->EnabledComponentUpdates()),
ids(ids),
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) {}
UpdateContext::~UpdateContext() {}
UpdateEngine::UpdateEngine(
const scoped_refptr<Configurator>& config,
UpdateChecker::Factory update_checker_factory,
CrxDownloader::Factory crx_downloader_factory,
PingManager* ping_manager,
const NotifyObserversCallback& notify_observers_callback)
: config_(config),
update_checker_factory_(update_checker_factory),
crx_downloader_factory_(crx_downloader_factory),
ping_manager_(ping_manager),
metadata_(new PersistedData(config->GetPrefService())),
notify_observers_callback_(notify_observers_callback) {}
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,
const UpdateClient::CrxDataCallback& crx_data_callback,
const Callback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
if (IsThrottled(is_foreground)) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(callback, Error::RETRY_LATER));
return;
}
std::unique_ptr<UpdateContext> update_context(new UpdateContext(
config_, is_foreground, ids, crx_data_callback,
notify_observers_callback_, callback, update_checker_factory_,
crx_downloader_factory_, ping_manager_));
CrxUpdateItem update_item;
std::unique_ptr<ActionUpdateCheck> update_check_action(new ActionUpdateCheck(
(*update_context->update_checker_factory)(config_, metadata_.get()),
config_->GetBrowserVersion(), config_->ExtraRequestParams()));
update_context->current_action.reset(update_check_action.release());
update_contexts_.insert(update_context.get());
update_context->current_action->Run(
update_context.get(),
base::Bind(&UpdateEngine::UpdateComplete, base::Unretained(this),
update_context.get()));
ignore_result(update_context.release());
}
void UpdateEngine::UpdateComplete(UpdateContext* update_context, Error error) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(update_contexts_.find(update_context) != update_contexts_.end());
const int throttle_sec(update_context->retry_after_sec_);
DCHECK_LE(throttle_sec, 24 * 60 * 60);
// 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)
throttle_updates_until_ =
throttle_sec
? base::TimeTicks::Now() +
base::TimeDelta::FromSeconds(throttle_sec)
: base::TimeTicks();
auto callback = update_context->callback;
update_contexts_.erase(update_context);
delete update_context;
callback.Run(error);
}
bool UpdateEngine::IsThrottled(bool is_foreground) const {
if (is_foreground || throttle_updates_until_.is_null())
return false;
const auto now(base::TimeTicks::Now());
// Throttle the calls in the interval (t - 1 day, t) to limit the effect of
// unset clocks or clock drift.
return throttle_updates_until_ - base::TimeDelta::FromDays(1) < now &&
now < throttle_updates_until_;
}
} // namespace update_client