Update V8 to version 4.7.1.
[chromium-blink-merge.git] / components / component_updater / component_updater_service.cc
blob29b120ea45bf5c81581f424aa4138a2806b9703a
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/component_updater/component_updater_service.h"
7 #include <algorithm>
8 #include <map>
9 #include <string>
10 #include <utility>
11 #include <vector>
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/callback.h"
16 #include "base/compiler_specific.h"
17 #include "base/files/file_path.h"
18 #include "base/files/file_util.h"
19 #include "base/logging.h"
20 #include "base/macros.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/sequenced_task_runner.h"
23 #include "base/single_thread_task_runner.h"
24 #include "base/thread_task_runner_handle.h"
25 #include "base/threading/sequenced_worker_pool.h"
26 #include "base/threading/thread_checker.h"
27 #include "base/timer/timer.h"
28 #include "components/component_updater/component_updater_service_internal.h"
29 #include "components/component_updater/timer.h"
30 #include "components/update_client/configurator.h"
31 #include "components/update_client/crx_update_item.h"
32 #include "components/update_client/update_client.h"
33 #include "components/update_client/utils.h"
34 #include "url/gurl.h"
36 using CrxInstaller = update_client::CrxInstaller;
37 using UpdateClient = update_client::UpdateClient;
39 namespace component_updater {
41 CrxUpdateService::CrxUpdateService(
42 const scoped_refptr<Configurator>& config,
43 const scoped_refptr<UpdateClient>& update_client)
44 : config_(config),
45 update_client_(update_client),
46 blocking_task_runner_(config->GetSequencedTaskRunner()) {
47 AddObserver(this);
50 CrxUpdateService::~CrxUpdateService() {
51 DCHECK(thread_checker_.CalledOnValidThread());
53 for (const auto item : ready_callbacks_) {
54 item.second.Run();
57 RemoveObserver(this);
59 Stop();
62 void CrxUpdateService::AddObserver(Observer* observer) {
63 DCHECK(thread_checker_.CalledOnValidThread());
64 update_client_->AddObserver(observer);
67 void CrxUpdateService::RemoveObserver(Observer* observer) {
68 DCHECK(thread_checker_.CalledOnValidThread());
69 update_client_->RemoveObserver(observer);
72 void CrxUpdateService::Start() {
73 DCHECK(thread_checker_.CalledOnValidThread());
74 VLOG(1) << "CrxUpdateService starting up. "
75 << "First update attempt will take place in "
76 << config_->InitialDelay() << " seconds. "
77 << "Next update attempt will take place in "
78 << config_->NextCheckDelay() << " seconds. ";
80 timer_.Start(
81 base::TimeDelta::FromSeconds(config_->InitialDelay()),
82 base::TimeDelta::FromSeconds(config_->NextCheckDelay()),
83 base::Bind(base::IgnoreResult(&CrxUpdateService::CheckForUpdates),
84 base::Unretained(this)));
87 // Stops the update loop. In flight operations will be completed.
88 void CrxUpdateService::Stop() {
89 DCHECK(thread_checker_.CalledOnValidThread());
90 VLOG(1) << "CrxUpdateService stopping";
91 timer_.Stop();
94 // Adds a component to be checked for upgrades. If the component exists it
95 // it will be replaced.
96 bool CrxUpdateService::RegisterComponent(const CrxComponent& component) {
97 DCHECK(thread_checker_.CalledOnValidThread());
98 if (component.pk_hash.empty() || !component.version.IsValid() ||
99 !component.installer) {
100 return false;
103 // Update the registration data if the component has been registered before.
104 const std::string id(GetCrxComponentID(component));
105 auto it = components_.find(id);
106 if (it != components_.end()) {
107 it->second = component;
108 return true;
111 components_.insert(std::make_pair(id, component));
112 components_order_.push_back(id);
114 // Create an initial state for this component. The state is mutated in
115 // response to events from the UpdateClient instance.
116 CrxUpdateItem item;
117 item.id = id;
118 item.component = component;
119 const auto inserted = component_states_.insert(std::make_pair(id, item));
120 DCHECK(inserted.second);
122 // Start the timer if this is the first component registered. The first timer
123 // event occurs after an interval defined by the component update
124 // configurator. The subsequent timer events are repeated with a period
125 // defined by the same configurator.
126 if (components_.size() == 1)
127 Start();
129 return true;
132 bool CrxUpdateService::UnregisterComponent(const std::string& id) {
133 DCHECK(thread_checker_.CalledOnValidThread());
134 auto it = components_.find(id);
135 if (it == components_.end())
136 return false;
138 DCHECK_EQ(id, it->first);
140 // Delay the uninstall of the component if the component is being updated.
141 if (update_client_->IsUpdating(id)) {
142 components_pending_unregistration_.push_back(id);
143 return true;
146 return DoUnregisterComponent(it->second);
149 bool CrxUpdateService::DoUnregisterComponent(const CrxComponent& component) {
150 DCHECK(thread_checker_.CalledOnValidThread());
152 const auto id = GetCrxComponentID(component);
153 DCHECK(ready_callbacks_.find(id) == ready_callbacks_.end());
155 const bool result = component.installer->Uninstall();
157 const auto pos =
158 std::find(components_order_.begin(), components_order_.end(), id);
159 if (pos != components_order_.end())
160 components_order_.erase(pos);
162 components_.erase(id);
163 component_states_.erase(id);
165 return result;
168 std::vector<std::string> CrxUpdateService::GetComponentIDs() const {
169 DCHECK(thread_checker_.CalledOnValidThread());
170 std::vector<std::string> ids;
171 for (const auto& it : components_)
172 ids.push_back(it.first);
173 return ids;
176 OnDemandUpdater& CrxUpdateService::GetOnDemandUpdater() {
177 DCHECK(thread_checker_.CalledOnValidThread());
178 return *this;
181 const CrxComponent* CrxUpdateService::GetComponent(
182 const std::string& id) const {
183 DCHECK(thread_checker_.CalledOnValidThread());
184 const auto it(components_.find(id));
185 return it != components_.end() ? &(it->second) : NULL;
188 const CrxUpdateItem* CrxUpdateService::GetComponentState(
189 const std::string& id) const {
190 DCHECK(thread_checker_.CalledOnValidThread());
191 const auto it(component_states_.find(id));
192 return it != component_states_.end() ? &it->second : NULL;
195 void CrxUpdateService::MaybeThrottle(const std::string& id,
196 const base::Closure& callback) {
197 DCHECK(thread_checker_.CalledOnValidThread());
198 auto it = components_.find(id);
199 if (it != components_.end()) {
200 DCHECK_EQ(it->first, id);
201 if (OnDemandUpdateWithCooldown(id)) {
202 ready_callbacks_.insert(std::make_pair(id, callback));
203 return;
207 callback.Run(); // Unblock the request if the request can't be throttled.
210 bool CrxUpdateService::OnDemandUpdate(const std::string& id) {
211 DCHECK(thread_checker_.CalledOnValidThread());
213 if (!GetComponent(id))
214 return false;
216 return OnDemandUpdateInternal(id);
219 bool CrxUpdateService::OnDemandUpdateWithCooldown(const std::string& id) {
220 DCHECK(thread_checker_.CalledOnValidThread());
222 DCHECK(GetComponent(id));
224 // Check if the request is too soon.
225 const auto component_state(GetComponentState(id));
226 if (component_state) {
227 base::TimeDelta delta = base::Time::Now() - component_state->last_check;
228 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
229 return false;
232 return OnDemandUpdateInternal(id);
235 bool CrxUpdateService::OnDemandUpdateInternal(const std::string& id) {
236 DCHECK(thread_checker_.CalledOnValidThread());
238 update_client_->Install(
239 id, base::Bind(&CrxUpdateService::OnUpdate, base::Unretained(this)),
240 base::Bind(&CrxUpdateService::OnUpdateComplete, base::Unretained(this)));
242 return true;
245 bool CrxUpdateService::CheckForUpdates() {
246 DCHECK(thread_checker_.CalledOnValidThread());
247 std::vector<std::string> ids;
248 for (const auto id : components_order_) {
249 DCHECK(components_.find(id) != components_.end());
250 ids.push_back(id);
253 update_client_->Update(
254 ids, base::Bind(&CrxUpdateService::OnUpdate, base::Unretained(this)),
255 base::Bind(&CrxUpdateService::OnUpdateComplete, base::Unretained(this)));
257 return true;
260 scoped_refptr<base::SequencedTaskRunner>
261 CrxUpdateService::GetSequencedTaskRunner() {
262 DCHECK(thread_checker_.CalledOnValidThread());
263 return blocking_task_runner_;
266 bool CrxUpdateService::GetComponentDetails(const std::string& id,
267 CrxUpdateItem* item) const {
268 DCHECK(thread_checker_.CalledOnValidThread());
270 // First, if this component is currently being updated, return its state from
271 // the update client.
272 if (update_client_->GetCrxUpdateState(id, item))
273 return true;
275 // Otherwise, return the last seen state of the component, if such a
276 // state exists.
277 const auto component_states_it = component_states_.find(id);
278 if (component_states_it != component_states_.end()) {
279 *item = component_states_it->second;
280 return true;
283 return false;
286 void CrxUpdateService::OnUpdate(const std::vector<std::string>& ids,
287 std::vector<CrxComponent>* components) {
288 DCHECK(thread_checker_.CalledOnValidThread());
289 DCHECK(components->empty());
291 for (const auto& id : ids) {
292 const auto registered_component(GetComponent(id));
293 if (registered_component) {
294 components->push_back(*registered_component);
299 void CrxUpdateService::OnUpdateComplete(int error) {
300 DCHECK(thread_checker_.CalledOnValidThread());
301 VLOG(1) << "Update completed with error " << error;
303 for (const auto id : components_pending_unregistration_) {
304 if (!update_client_->IsUpdating(id)) {
305 const auto component = GetComponent(id);
306 if (component)
307 DoUnregisterComponent(*component);
312 void CrxUpdateService::OnEvent(Events event, const std::string& id) {
313 DCHECK(thread_checker_.CalledOnValidThread());
315 // Unblock all throttles for the component.
316 if (event == Observer::Events::COMPONENT_UPDATED ||
317 event == Observer::Events::COMPONENT_NOT_UPDATED) {
318 auto callbacks = ready_callbacks_.equal_range(id);
319 for (auto it = callbacks.first; it != callbacks.second; ++it) {
320 it->second.Run();
322 ready_callbacks_.erase(id);
325 CrxUpdateItem update_item;
326 if (!update_client_->GetCrxUpdateState(id, &update_item))
327 return;
329 // Update the state of the item.
330 auto it = component_states_.find(id);
331 DCHECK(it != component_states_.end());
332 it->second = update_item;
334 // Update the component registration with the new version.
335 if (event == Observer::Events::COMPONENT_UPDATED) {
336 auto component(const_cast<CrxComponent*>(GetComponent(id)));
337 if (component) {
338 component->version = update_item.next_version;
339 component->fingerprint = update_item.next_fp;
344 ///////////////////////////////////////////////////////////////////////////////
346 // The component update factory. Using the component updater as a singleton
347 // is the job of the browser process.
348 // TODO(sorin): consider making this a singleton.
349 scoped_ptr<ComponentUpdateService> ComponentUpdateServiceFactory(
350 const scoped_refptr<Configurator>& config) {
351 DCHECK(config);
352 auto update_client = update_client::UpdateClientFactory(config);
353 return scoped_ptr<ComponentUpdateService>(
354 new CrxUpdateService(config, update_client.Pass()));
357 } // namespace component_updater