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"
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"
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
)
45 update_client_(update_client
),
46 blocking_task_runner_(config
->GetSequencedTaskRunner()) {
50 CrxUpdateService::~CrxUpdateService() {
51 DCHECK(thread_checker_
.CalledOnValidThread());
53 for (const auto item
: ready_callbacks_
) {
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. ";
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";
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
) {
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
;
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.
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)
132 bool CrxUpdateService::UnregisterComponent(const std::string
& id
) {
133 DCHECK(thread_checker_
.CalledOnValidThread());
134 auto it
= components_
.find(id
);
135 if (it
== components_
.end())
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
);
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();
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
);
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
);
176 OnDemandUpdater
& CrxUpdateService::GetOnDemandUpdater() {
177 DCHECK(thread_checker_
.CalledOnValidThread());
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
));
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
))
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()))
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)));
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());
253 update_client_
->Update(
254 ids
, base::Bind(&CrxUpdateService::OnUpdate
, base::Unretained(this)),
255 base::Bind(&CrxUpdateService::OnUpdateComplete
, base::Unretained(this)));
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
))
275 // Otherwise, return the last seen state of the component, if such a
277 const auto component_states_it
= component_states_
.find(id
);
278 if (component_states_it
!= component_states_
.end()) {
279 *item
= component_states_it
->second
;
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
);
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
) {
322 ready_callbacks_
.erase(id
);
325 CrxUpdateItem update_item
;
326 if (!update_client_
->GetCrxUpdateState(id
, &update_item
))
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
)));
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
) {
352 auto update_client
= update_client::UpdateClientFactory(config
);
353 return scoped_ptr
<ComponentUpdateService
>(
354 new CrxUpdateService(config
, update_client
.Pass()));
357 } // namespace component_updater