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"
11 #include "base/at_exit.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/compiler_specific.h"
16 #include "base/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/logging.h"
19 #include "base/macros.h"
20 #include "base/memory/scoped_ptr.h"
21 #include "base/message_loop/message_loop_proxy.h"
22 #include "base/observer_list.h"
23 #include "base/sequenced_task_runner.h"
24 #include "base/stl_util.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/update_client/component_patcher_operation.h"
29 #include "components/update_client/component_unpacker.h"
30 #include "components/update_client/configurator.h"
31 #include "components/update_client/crx_downloader.h"
32 #include "components/update_client/crx_update_item.h"
33 #include "components/update_client/ping_manager.h"
34 #include "components/update_client/update_checker.h"
35 #include "components/update_client/update_client.h"
36 #include "components/update_client/update_response.h"
37 #include "components/update_client/utils.h"
40 using update_client::CrxInstaller
;
41 using update_client::ComponentUnpacker
;
42 using update_client::Configurator
;
43 using update_client::CrxComponent
;
44 using update_client::CrxDownloader
;
45 using update_client::CrxUpdateItem
;
46 using update_client::PingManager
;
47 using update_client::UpdateChecker
;
48 using update_client::UpdateResponse
;
50 namespace component_updater
{
52 // The component updater is designed to live until process shutdown, so
53 // base::Bind() calls are not refcounted.
57 // Returns true if the |proposed| version is newer than |current| version.
58 bool IsVersionNewer(const Version
& current
, const std::string
& proposed
) {
59 Version
proposed_ver(proposed
);
60 return proposed_ver
.IsValid() && current
.CompareTo(proposed_ver
) < 0;
63 // Returns true if a differential update is available, it has not failed yet,
64 // and the configuration allows it.
65 bool CanTryDiffUpdate(const CrxUpdateItem
* update_item
,
66 const Configurator
& config
) {
67 return HasDiffUpdate(update_item
) && !update_item
->diff_update_failed
&&
68 config
.DeltasEnabled();
71 void AppendDownloadMetrics(
72 const std::vector
<CrxDownloader::DownloadMetrics
>& source
,
73 std::vector
<CrxDownloader::DownloadMetrics
>* destination
) {
74 destination
->insert(destination
->end(), source
.begin(), source
.end());
79 //////////////////////////////////////////////////////////////////////////////
80 // The one and only implementation of the ComponentUpdateService interface. In
81 // charge of running the show. The main method is ProcessPendingItems() which
82 // is called periodically to do the upgrades/installs or the update checks.
83 // An important consideration here is to be as "low impact" as we can to the
84 // rest of the browser, so even if we have many components registered and
85 // eligible for update, we only do one thing at a time with pauses in between
86 // the tasks. Also when we do network requests there is only one |url_fetcher_|
87 // in flight at a time.
88 // There are no locks in this code, the main structure |work_items_| is mutated
89 // only from the main thread. The unpack and installation is done in a blocking
90 // pool thread. The network requests are done in the IO thread or in the file
92 class CrxUpdateService
: public ComponentUpdateService
, public OnDemandUpdater
{
94 explicit CrxUpdateService(const scoped_refptr
<Configurator
>& config
);
95 ~CrxUpdateService() override
;
97 // Overrides for ComponentUpdateService.
98 void AddObserver(Observer
* observer
) override
;
99 void RemoveObserver(Observer
* observer
) override
;
100 Status
Start() override
;
101 Status
Stop() override
;
102 Status
RegisterComponent(const CrxComponent
& component
) override
;
103 Status
UnregisterComponent(const std::string
& crx_id
) override
;
104 std::vector
<std::string
> GetComponentIDs() const override
;
105 OnDemandUpdater
& GetOnDemandUpdater() override
;
106 void MaybeThrottle(const std::string
& crx_id
,
107 const base::Closure
& callback
) override
;
108 scoped_refptr
<base::SequencedTaskRunner
> GetSequencedTaskRunner() override
;
110 // Context for a crx download url request.
112 scoped_refptr
<CrxInstaller
> installer
;
113 std::vector
<uint8_t> pk_hash
;
115 std::string fingerprint
;
116 CRXContext() : installer(NULL
) {}
127 enum StepDelayInterval
{
133 // Overrides for ComponentUpdateService.
134 bool GetComponentDetails(const std::string
& component_id
,
135 CrxUpdateItem
* item
) const override
;
137 // Overrides for OnDemandUpdater.
138 Status
OnDemandUpdate(const std::string
& component_id
) override
;
140 void UpdateCheckComplete(const GURL
& original_url
,
142 const std::string
& error_message
,
143 const UpdateResponse::Results
& results
);
144 void OnUpdateCheckSucceeded(const UpdateResponse::Results
& results
);
145 void OnUpdateCheckFailed(int error
, const std::string
& error_message
);
147 void DownloadProgress(const std::string
& component_id
,
148 const CrxDownloader::Result
& download_result
);
150 void DownloadComplete(scoped_ptr
<CRXContext
> crx_context
,
151 const CrxDownloader::Result
& download_result
);
153 Status
OnDemandUpdateInternal(CrxUpdateItem
* item
);
154 Status
OnDemandUpdateWithCooldown(CrxUpdateItem
* item
);
156 void ProcessPendingItems();
158 // Uninstall and remove all unregistered work items.
159 void UninstallUnregisteredItems();
161 // Find a component that is ready to update.
162 CrxUpdateItem
* FindReadyComponent() const;
164 // Prepares the components for an update check and initiates the request.
165 // Returns true if an update check request has been made. Returns false if
166 // no update check was needed or an error occured.
167 bool CheckForUpdates();
169 void UpdateComponent(CrxUpdateItem
* workitem
);
171 void ScheduleNextRun(StepDelayInterval step_delay
);
173 void ParseResponse(const std::string
& xml
);
175 void Install(scoped_ptr
<CRXContext
> context
, const base::FilePath
& crx_path
);
177 void EndUnpacking(const std::string
& component_id
,
178 const base::FilePath
& crx_path
,
179 ComponentUnpacker::Error error
,
182 void DoneInstalling(const std::string
& component_id
,
183 ComponentUnpacker::Error error
,
186 void ChangeItemState(CrxUpdateItem
* item
, CrxUpdateItem::State to
);
188 size_t ChangeItemStatus(CrxUpdateItem::State from
, CrxUpdateItem::State to
);
190 CrxUpdateItem
* FindUpdateItemById(const std::string
& id
) const;
192 void NotifyObservers(Observer::Events event
, const std::string
& id
);
194 bool HasOnDemandItems() const;
196 Status
GetServiceStatus(const CrxUpdateItem::State state
);
198 scoped_refptr
<Configurator
> config_
;
200 scoped_ptr
<UpdateChecker
> update_checker_
;
202 scoped_ptr
<PingManager
> ping_manager_
;
204 scoped_refptr
<ComponentUnpacker
> unpacker_
;
206 scoped_ptr
<CrxDownloader
> crx_downloader_
;
208 // A collection of every work item.
209 typedef std::vector
<CrxUpdateItem
*> UpdateItems
;
210 UpdateItems work_items_
;
212 base::OneShotTimer
<CrxUpdateService
> timer_
;
214 base::ThreadChecker thread_checker_
;
216 // Used to post responses back to the main thread.
217 scoped_refptr
<base::SingleThreadTaskRunner
> main_task_runner_
;
219 scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner_
;
223 ObserverList
<Observer
> observer_list_
;
225 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService
);
228 //////////////////////////////////////////////////////////////////////////////
230 CrxUpdateService::CrxUpdateService(const scoped_refptr
<Configurator
>& config
)
232 ping_manager_(new PingManager(*config
)),
233 main_task_runner_(base::MessageLoopProxy::current()),
234 blocking_task_runner_(config
->GetSequencedTaskRunner()),
238 CrxUpdateService::~CrxUpdateService() {
239 // Because we are a singleton, at this point only the main thread should be
240 // alive, this simplifies the management of the work that could be in
241 // flight in other threads.
243 STLDeleteElements(&work_items_
);
246 void CrxUpdateService::AddObserver(Observer
* observer
) {
247 DCHECK(thread_checker_
.CalledOnValidThread());
248 observer_list_
.AddObserver(observer
);
251 void CrxUpdateService::RemoveObserver(Observer
* observer
) {
252 DCHECK(thread_checker_
.CalledOnValidThread());
253 observer_list_
.RemoveObserver(observer
);
256 ComponentUpdateService::Status
CrxUpdateService::Start() {
257 // Note that RegisterComponent will call Start() when the first
258 // component is registered, so it can be called twice. This way
259 // we avoid scheduling the timer if there is no work to do.
260 VLOG(1) << "CrxUpdateService starting up";
262 if (work_items_
.empty())
265 NotifyObservers(Observer::Events::COMPONENT_UPDATER_STARTED
, "");
267 VLOG(1) << "First update attempt will take place in "
268 << config_
->InitialDelay() << " seconds";
269 timer_
.Start(FROM_HERE
,
270 base::TimeDelta::FromSeconds(config_
->InitialDelay()),
272 &CrxUpdateService::ProcessPendingItems
);
276 // Stop the main check + update loop. In flight operations will be
278 ComponentUpdateService::Status
CrxUpdateService::Stop() {
279 VLOG(1) << "CrxUpdateService stopping";
285 bool CrxUpdateService::HasOnDemandItems() const {
288 static bool IsOnDemand(CrxUpdateItem
* item
) { return item
->on_demand
; }
290 return std::find_if(work_items_
.begin(),
292 Helper::IsOnDemand
) != work_items_
.end();
295 // This function sets the timer which will call ProcessPendingItems() or
296 // ProcessRequestedItem() if there is an on_demand item. There
297 // are three kinds of waits:
298 // - a short delay, when there is immediate work to be done.
299 // - a medium delay, when there are updates to be applied within the current
300 // update cycle, or there are components that are still unchecked.
301 // - a long delay when a full check/update cycle has completed for all
303 void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay
) {
304 DCHECK(thread_checker_
.CalledOnValidThread());
305 DCHECK(!update_checker_
);
306 CHECK(!timer_
.IsRunning());
307 // It could be the case that Stop() had been called while a url request
308 // or unpacking was in flight, if so we arrive here but |running_| is
309 // false. In that case do not loop again.
313 // Keep the delay short if in the middle of an update (step_delay),
314 // or there are new requested_work_items_ that have not been processed yet.
315 int64_t delay_seconds
= 0;
316 if (!HasOnDemandItems()) {
317 switch (step_delay
) {
318 case kStepDelayShort
:
319 delay_seconds
= config_
->StepDelay();
321 case kStepDelayMedium
:
322 delay_seconds
= config_
->StepDelayMedium();
325 delay_seconds
= config_
->NextCheckDelay();
329 delay_seconds
= config_
->StepDelay();
332 if (step_delay
!= kStepDelayShort
) {
333 NotifyObservers(Observer::Events::COMPONENT_UPDATER_SLEEPING
, "");
335 // Zero is only used for unit tests.
336 if (0 == delay_seconds
)
340 VLOG(1) << "Scheduling next run to occur in " << delay_seconds
<< " seconds";
341 timer_
.Start(FROM_HERE
,
342 base::TimeDelta::FromSeconds(delay_seconds
),
344 &CrxUpdateService::ProcessPendingItems
);
347 // Given a extension-like component id, find the associated component.
348 CrxUpdateItem
* CrxUpdateService::FindUpdateItemById(
349 const std::string
& id
) const {
350 DCHECK(thread_checker_
.CalledOnValidThread());
351 CrxUpdateItem::FindById
finder(id
);
352 UpdateItems::const_iterator it
=
353 std::find_if(work_items_
.begin(), work_items_
.end(), finder
);
354 return it
!= work_items_
.end() ? *it
: NULL
;
357 // Changes a component's state, clearing on_demand and firing notifications as
358 // necessary. By convention, this is the only function that can change a
359 // CrxUpdateItem's |state|.
360 // TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
361 void CrxUpdateService::ChangeItemState(CrxUpdateItem
* item
,
362 CrxUpdateItem::State to
) {
363 DCHECK(thread_checker_
.CalledOnValidThread());
364 if (to
== CrxUpdateItem::State::kNoUpdate
||
365 to
== CrxUpdateItem::State::kUpdated
||
366 to
== CrxUpdateItem::State::kUpToDate
) {
367 item
->on_demand
= false;
373 case CrxUpdateItem::State::kCanUpdate
:
374 NotifyObservers(Observer::Events::COMPONENT_UPDATE_FOUND
, item
->id
);
376 case CrxUpdateItem::State::kUpdatingDiff
:
377 case CrxUpdateItem::State::kUpdating
:
378 NotifyObservers(Observer::Events::COMPONENT_UPDATE_READY
, item
->id
);
380 case CrxUpdateItem::State::kUpdated
:
381 NotifyObservers(Observer::Events::COMPONENT_UPDATED
, item
->id
);
383 case CrxUpdateItem::State::kUpToDate
:
384 case CrxUpdateItem::State::kNoUpdate
:
385 NotifyObservers(Observer::Events::COMPONENT_NOT_UPDATED
, item
->id
);
387 case CrxUpdateItem::State::kNew
:
388 case CrxUpdateItem::State::kChecking
:
389 case CrxUpdateItem::State::kDownloading
:
390 case CrxUpdateItem::State::kDownloadingDiff
:
391 case CrxUpdateItem::State::kDownloaded
:
392 case CrxUpdateItem::State::kLastStatus
:
393 // No notification for these states.
397 // Free possible pending network requests.
398 if ((to
== CrxUpdateItem::State::kUpdated
) ||
399 (to
== CrxUpdateItem::State::kUpToDate
) ||
400 (to
== CrxUpdateItem::State::kNoUpdate
)) {
401 for (std::vector
<base::Closure
>::iterator it
=
402 item
->ready_callbacks
.begin();
403 it
!= item
->ready_callbacks
.end();
407 item
->ready_callbacks
.clear();
411 // Changes all the components in |work_items_| that have |from| state to
412 // |to| state and returns how many have been changed.
413 size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::State from
,
414 CrxUpdateItem::State to
) {
415 DCHECK(thread_checker_
.CalledOnValidThread());
417 for (UpdateItems::iterator it
= work_items_
.begin();
418 it
!= work_items_
.end();
420 CrxUpdateItem
* item
= *it
;
421 if (item
->state
== from
) {
422 ChangeItemState(item
, to
);
429 // Adds a component to be checked for upgrades. If the component exists it
430 // it will be replaced and the return code is Status::kReplaced.
431 ComponentUpdateService::Status
CrxUpdateService::RegisterComponent(
432 const CrxComponent
& component
) {
433 DCHECK(thread_checker_
.CalledOnValidThread());
434 if (component
.pk_hash
.empty() || !component
.version
.IsValid() ||
435 !component
.installer
)
436 return Status::kError
;
438 std::string
id(GetCrxComponentID(component
));
439 CrxUpdateItem
* uit
= FindUpdateItemById(id
);
441 uit
->component
= component
;
442 uit
->unregistered
= false;
443 return Status::kReplaced
;
446 uit
= new CrxUpdateItem
;
448 uit
->component
= component
;
450 work_items_
.push_back(uit
);
452 // If this is the first component registered we call Start to
453 // schedule the first timer. Otherwise, reset the timer to trigger another
454 // pass over the work items, if the component updater is sleeping, fact
455 // indicated by a running timer. If the timer is not running, it means that
456 // the service is busy updating something, and in that case, this component
457 // will be picked up at the next pass.
459 if (work_items_
.size() == 1) {
461 } else if (timer_
.IsRunning()) {
462 timer_
.Start(FROM_HERE
,
463 base::TimeDelta::FromSeconds(config_
->InitialDelay()),
465 &CrxUpdateService::ProcessPendingItems
);
472 ComponentUpdateService::Status
CrxUpdateService::UnregisterComponent(
473 const std::string
& crx_id
) {
474 auto it
= std::find_if(work_items_
.begin(), work_items_
.end(),
475 CrxUpdateItem::FindById(crx_id
));
476 if (it
== work_items_
.end())
477 return Status::kError
;
479 (*it
)->unregistered
= true;
481 ScheduleNextRun(kStepDelayShort
);
485 std::vector
<std::string
> CrxUpdateService::GetComponentIDs() const {
486 DCHECK(thread_checker_
.CalledOnValidThread());
487 std::vector
<std::string
> component_ids
;
488 for (UpdateItems::const_iterator it
= work_items_
.begin();
489 it
!= work_items_
.end();
491 const CrxUpdateItem
* item
= *it
;
492 component_ids
.push_back(item
->id
);
494 return component_ids
;
497 OnDemandUpdater
& CrxUpdateService::GetOnDemandUpdater() {
501 void CrxUpdateService::MaybeThrottle(const std::string
& crx_id
,
502 const base::Closure
& callback
) {
503 DCHECK(thread_checker_
.CalledOnValidThread());
504 // Check if we can on-demand update, else unblock the request anyway.
505 CrxUpdateItem
* item
= FindUpdateItemById(crx_id
);
506 Status status
= OnDemandUpdateWithCooldown(item
);
507 if (status
== Status::kOk
|| status
== Status::kInProgress
) {
508 item
->ready_callbacks
.push_back(callback
);
514 scoped_refptr
<base::SequencedTaskRunner
>
515 CrxUpdateService::GetSequencedTaskRunner() {
516 return blocking_task_runner_
;
519 bool CrxUpdateService::GetComponentDetails(const std::string
& component_id
,
520 CrxUpdateItem
* item
) const {
521 DCHECK(thread_checker_
.CalledOnValidThread());
522 const CrxUpdateItem
* crx_update_item(FindUpdateItemById(component_id
));
524 *item
= *crx_update_item
;
525 return crx_update_item
!= NULL
;
528 // Start the process of checking for an update, for a particular component
529 // that was previously registered.
530 // |component_id| is a value returned from GetCrxComponentID().
531 ComponentUpdateService::Status
CrxUpdateService::OnDemandUpdate(
532 const std::string
& component_id
) {
533 return OnDemandUpdateInternal(FindUpdateItemById(component_id
));
536 // This is the main loop of the component updater. It updates one component
537 // at a time if updates are available. Otherwise, it does an update check or
538 // takes a long sleep until the loop runs again.
539 void CrxUpdateService::ProcessPendingItems() {
540 DCHECK(thread_checker_
.CalledOnValidThread());
542 CrxUpdateItem
* ready_upgrade
= FindReadyComponent();
544 UpdateComponent(ready_upgrade
);
548 UninstallUnregisteredItems();
550 if (!CheckForUpdates())
551 ScheduleNextRun(kStepDelayLong
);
554 void CrxUpdateService::UninstallUnregisteredItems() {
555 std::vector
<CrxUpdateItem
*> new_work_items
;
556 for (CrxUpdateItem
* item
: work_items_
) {
557 scoped_ptr
<CrxUpdateItem
> owned_item(item
);
558 if (owned_item
->unregistered
) {
559 const bool success
= owned_item
->component
.installer
->Uninstall();
562 new_work_items
.push_back(owned_item
.release());
565 new_work_items
.swap(work_items_
);
568 CrxUpdateItem
* CrxUpdateService::FindReadyComponent() const {
571 static bool IsReadyOnDemand(CrxUpdateItem
* item
) {
572 return item
->on_demand
&& IsReady(item
);
574 static bool IsReady(CrxUpdateItem
* item
) {
575 return item
->state
== CrxUpdateItem::State::kCanUpdate
;
579 std::vector
<CrxUpdateItem
*>::const_iterator it
= std::find_if(
580 work_items_
.begin(), work_items_
.end(), Helper::IsReadyOnDemand
);
581 if (it
!= work_items_
.end())
583 it
= std::find_if(work_items_
.begin(), work_items_
.end(), Helper::IsReady
);
584 if (it
!= work_items_
.end())
589 // Prepares the components for an update check and initiates the request.
590 // On demand components are always included in the update check request.
591 // Otherwise, only include components that have not been checked recently.
592 bool CrxUpdateService::CheckForUpdates() {
593 const base::TimeDelta minimum_recheck_wait_time
=
594 base::TimeDelta::FromSeconds(config_
->MinimumReCheckWait());
595 const base::Time
now(base::Time::Now());
597 std::vector
<CrxUpdateItem
*> items_to_check
;
598 for (size_t i
= 0; i
!= work_items_
.size(); ++i
) {
599 CrxUpdateItem
* item
= work_items_
[i
];
600 DCHECK(item
->state
== CrxUpdateItem::State::kNew
||
601 item
->state
== CrxUpdateItem::State::kNoUpdate
||
602 item
->state
== CrxUpdateItem::State::kUpToDate
||
603 item
->state
== CrxUpdateItem::State::kUpdated
);
605 const base::TimeDelta
time_since_last_checked(now
- item
->last_check
);
607 if (!item
->on_demand
&&
608 time_since_last_checked
< minimum_recheck_wait_time
) {
609 VLOG(1) << "Skipping check for component update: id=" << item
->id
610 << ", time_since_last_checked="
611 << time_since_last_checked
.InSeconds()
612 << " seconds: too soon to check for an update";
616 VLOG(1) << "Scheduling update check for component id=" << item
->id
617 << ", time_since_last_checked="
618 << time_since_last_checked
.InSeconds() << " seconds";
620 item
->last_check
= now
;
621 item
->crx_urls
.clear();
622 item
->crx_diffurls
.clear();
623 item
->previous_version
= item
->component
.version
;
624 item
->next_version
= Version();
625 item
->previous_fp
= item
->component
.fingerprint
;
626 item
->next_fp
.clear();
627 item
->diff_update_failed
= false;
628 item
->error_category
= 0;
629 item
->error_code
= 0;
630 item
->extra_code1
= 0;
631 item
->diff_error_category
= 0;
632 item
->diff_error_code
= 0;
633 item
->diff_extra_code1
= 0;
634 item
->download_metrics
.clear();
636 items_to_check
.push_back(item
);
638 ChangeItemState(item
, CrxUpdateItem::State::kChecking
);
641 if (items_to_check
.empty())
644 update_checker_
= UpdateChecker::Create(*config_
).Pass();
645 return update_checker_
->CheckForUpdates(
647 config_
->ExtraRequestParams(),
648 base::Bind(&CrxUpdateService::UpdateCheckComplete
,
649 base::Unretained(this)));
652 void CrxUpdateService::UpdateComponent(CrxUpdateItem
* workitem
) {
653 scoped_ptr
<CRXContext
> crx_context(new CRXContext
);
654 crx_context
->pk_hash
= workitem
->component
.pk_hash
;
655 crx_context
->id
= workitem
->id
;
656 crx_context
->installer
= workitem
->component
.installer
;
657 crx_context
->fingerprint
= workitem
->next_fp
;
658 const std::vector
<GURL
>* urls
= NULL
;
659 bool allow_background_download
= false;
660 if (CanTryDiffUpdate(workitem
, *config_
)) {
661 urls
= &workitem
->crx_diffurls
;
662 ChangeItemState(workitem
, CrxUpdateItem::State::kDownloadingDiff
);
664 // Background downloads are enabled only for selected components and
665 // only for full downloads (see issue 340448).
666 allow_background_download
= workitem
->component
.allow_background_download
;
667 urls
= &workitem
->crx_urls
;
668 ChangeItemState(workitem
, CrxUpdateItem::State::kDownloading
);
671 // On demand component updates are always downloaded in foreground.
672 const bool is_background_download
= !workitem
->on_demand
&&
673 allow_background_download
&&
674 config_
->UseBackgroundDownloader();
676 crx_downloader_
.reset(
677 CrxDownloader::Create(is_background_download
, config_
->RequestContext(),
678 blocking_task_runner_
,
679 config_
->GetSingleThreadTaskRunner()).release());
680 crx_downloader_
->set_progress_callback(
681 base::Bind(&CrxUpdateService::DownloadProgress
,
682 base::Unretained(this),
684 crx_downloader_
->StartDownload(*urls
,
685 base::Bind(&CrxUpdateService::DownloadComplete
,
686 base::Unretained(this),
687 base::Passed(&crx_context
)));
690 void CrxUpdateService::UpdateCheckComplete(
691 const GURL
& original_url
,
693 const std::string
& error_message
,
694 const UpdateResponse::Results
& results
) {
695 DCHECK(thread_checker_
.CalledOnValidThread());
696 VLOG(1) << "Update check completed from: " << original_url
.spec();
697 update_checker_
.reset();
699 OnUpdateCheckSucceeded(results
);
701 OnUpdateCheckFailed(error
, error_message
);
704 // Handles a valid Omaha update check response by matching the results with
705 // the registered components which were checked for updates.
706 // If updates are found, prepare the components for the actual version upgrade.
707 // One of these components will be drafted for the upgrade next time
708 // ProcessPendingItems is called.
709 void CrxUpdateService::OnUpdateCheckSucceeded(
710 const UpdateResponse::Results
& results
) {
711 size_t num_updates_pending
= 0;
712 DCHECK(thread_checker_
.CalledOnValidThread());
713 VLOG(1) << "Update check succeeded.";
714 std::vector
<UpdateResponse::Result
>::const_iterator it
;
715 for (it
= results
.list
.begin(); it
!= results
.list
.end(); ++it
) {
716 CrxUpdateItem
* crx
= FindUpdateItemById(it
->extension_id
);
720 if (crx
->state
!= CrxUpdateItem::State::kChecking
) {
722 continue; // Not updating this component now.
725 if (it
->manifest
.version
.empty()) {
726 // No version means no update available.
727 ChangeItemState(crx
, CrxUpdateItem::State::kNoUpdate
);
728 VLOG(1) << "No update available for component: " << crx
->id
;
732 if (!IsVersionNewer(crx
->component
.version
, it
->manifest
.version
)) {
733 // The component is up to date.
734 ChangeItemState(crx
, CrxUpdateItem::State::kUpToDate
);
735 VLOG(1) << "Component already up-to-date: " << crx
->id
;
739 if (!it
->manifest
.browser_min_version
.empty()) {
740 if (IsVersionNewer(config_
->GetBrowserVersion(),
741 it
->manifest
.browser_min_version
)) {
742 // The component is not compatible with this Chrome version.
743 VLOG(1) << "Ignoring incompatible component: " << crx
->id
;
744 ChangeItemState(crx
, CrxUpdateItem::State::kNoUpdate
);
749 if (it
->manifest
.packages
.size() != 1) {
750 // Assume one and only one package per component.
751 VLOG(1) << "Ignoring multiple packages for component: " << crx
->id
;
752 ChangeItemState(crx
, CrxUpdateItem::State::kNoUpdate
);
756 // Parse the members of the result and queue an upgrade for this component.
757 crx
->next_version
= Version(it
->manifest
.version
);
759 VLOG(1) << "Update found for component: " << crx
->id
;
761 typedef UpdateResponse::Result::Manifest::Package Package
;
762 const Package
& package(it
->manifest
.packages
[0]);
763 crx
->next_fp
= package
.fingerprint
;
765 // Resolve the urls by combining the base urls with the package names.
766 for (size_t i
= 0; i
!= it
->crx_urls
.size(); ++i
) {
767 const GURL
url(it
->crx_urls
[i
].Resolve(package
.name
));
769 crx
->crx_urls
.push_back(url
);
771 for (size_t i
= 0; i
!= it
->crx_diffurls
.size(); ++i
) {
772 const GURL
url(it
->crx_diffurls
[i
].Resolve(package
.namediff
));
774 crx
->crx_diffurls
.push_back(url
);
777 ChangeItemState(crx
, CrxUpdateItem::State::kCanUpdate
);
778 ++num_updates_pending
;
781 // All components that are not included in the update response are
782 // considered up to date.
783 ChangeItemStatus(CrxUpdateItem::State::kChecking
,
784 CrxUpdateItem::State::kUpToDate
);
786 // If there are updates pending we do a short wait, otherwise we take
787 // a longer delay until we check the components again.
788 ScheduleNextRun(num_updates_pending
> 0 ? kStepDelayShort
: kStepDelayLong
);
791 void CrxUpdateService::OnUpdateCheckFailed(int error
,
792 const std::string
& error_message
) {
793 DCHECK(thread_checker_
.CalledOnValidThread());
795 size_t count
= ChangeItemStatus(CrxUpdateItem::State::kChecking
,
796 CrxUpdateItem::State::kNoUpdate
);
797 DCHECK_GT(count
, 0ul);
798 VLOG(1) << "Update check failed.";
799 ScheduleNextRun(kStepDelayLong
);
802 // Called when progress is being made downloading a CRX. The progress may
803 // not monotonically increase due to how the CRX downloader switches between
804 // different downloaders and fallback urls.
805 void CrxUpdateService::DownloadProgress(
806 const std::string
& component_id
,
807 const CrxDownloader::Result
& download_result
) {
808 DCHECK(thread_checker_
.CalledOnValidThread());
809 NotifyObservers(Observer::Events::COMPONENT_UPDATE_DOWNLOADING
, component_id
);
812 // Called when the CRX package has been downloaded to a temporary location.
813 // Here we fire the notifications and schedule the component-specific installer
814 // to be called in the file thread.
815 void CrxUpdateService::DownloadComplete(
816 scoped_ptr
<CRXContext
> crx_context
,
817 const CrxDownloader::Result
& download_result
) {
818 DCHECK(thread_checker_
.CalledOnValidThread());
820 CrxUpdateItem
* crx
= FindUpdateItemById(crx_context
->id
);
822 DCHECK(crx
->state
== CrxUpdateItem::State::kDownloadingDiff
||
823 crx
->state
== CrxUpdateItem::State::kDownloading
);
825 AppendDownloadMetrics(crx_downloader_
->download_metrics(),
826 &crx
->download_metrics
);
828 crx_downloader_
.reset();
830 if (download_result
.error
) {
831 if (crx
->state
== CrxUpdateItem::State::kDownloadingDiff
) {
832 crx
->diff_error_category
= kNetworkError
;
833 crx
->diff_error_code
= download_result
.error
;
834 crx
->diff_update_failed
= true;
835 size_t count
= ChangeItemStatus(CrxUpdateItem::State::kDownloadingDiff
,
836 CrxUpdateItem::State::kCanUpdate
);
837 DCHECK_EQ(count
, 1ul);
839 ScheduleNextRun(kStepDelayShort
);
842 crx
->error_category
= kNetworkError
;
843 crx
->error_code
= download_result
.error
;
844 size_t count
= ChangeItemStatus(CrxUpdateItem::State::kDownloading
,
845 CrxUpdateItem::State::kNoUpdate
);
846 DCHECK_EQ(count
, 1ul);
848 // At this point, since both the differential and the full downloads failed,
849 // the update for this component has finished with an error.
850 ping_manager_
->OnUpdateComplete(crx
);
852 // Move on to the next update, if there is one available.
853 ScheduleNextRun(kStepDelayMedium
);
856 if (crx
->state
== CrxUpdateItem::State::kDownloadingDiff
) {
857 count
= ChangeItemStatus(CrxUpdateItem::State::kDownloadingDiff
,
858 CrxUpdateItem::State::kUpdatingDiff
);
860 count
= ChangeItemStatus(CrxUpdateItem::State::kDownloading
,
861 CrxUpdateItem::State::kUpdating
);
863 DCHECK_EQ(count
, 1ul);
865 // Why unretained? See comment at top of file.
866 blocking_task_runner_
->PostDelayedTask(
868 base::Bind(&CrxUpdateService::Install
,
869 base::Unretained(this),
870 base::Passed(&crx_context
),
871 download_result
.response
),
872 base::TimeDelta::FromMilliseconds(config_
->StepDelay()));
876 // Install consists of digital signature verification, unpacking and then
877 // calling the component specific installer. All that is handled by the
878 // |unpacker_|. If there is an error this function is in charge of deleting
879 // the files created.
880 void CrxUpdateService::Install(scoped_ptr
<CRXContext
> context
,
881 const base::FilePath
& crx_path
) {
882 // This function owns the file at |crx_path| and the |context| object.
883 unpacker_
= new ComponentUnpacker(context
->pk_hash
,
885 context
->fingerprint
,
887 config_
->CreateOutOfProcessPatcher(),
888 blocking_task_runner_
);
889 unpacker_
->Unpack(base::Bind(&CrxUpdateService::EndUnpacking
,
890 base::Unretained(this),
895 void CrxUpdateService::EndUnpacking(const std::string
& component_id
,
896 const base::FilePath
& crx_path
,
897 ComponentUnpacker::Error error
,
898 int extended_error
) {
899 if (!update_client::DeleteFileAndEmptyParentDirectory(crx_path
))
900 NOTREACHED() << crx_path
.value();
901 main_task_runner_
->PostDelayedTask(
903 base::Bind(&CrxUpdateService::DoneInstalling
,
904 base::Unretained(this),
908 base::TimeDelta::FromMilliseconds(config_
->StepDelay()));
909 // Reset the unpacker last, otherwise we free our own arguments.
913 // Installation has been completed. Adjust the component state and
914 // schedule the next check. Schedule a short delay before trying the full
915 // update when the differential update failed.
916 void CrxUpdateService::DoneInstalling(const std::string
& component_id
,
917 ComponentUnpacker::Error error
,
919 DCHECK(thread_checker_
.CalledOnValidThread());
921 ErrorCategory error_category
= kErrorNone
;
923 case ComponentUnpacker::kNone
:
925 case ComponentUnpacker::kInstallerError
:
926 error_category
= kInstallError
;
929 error_category
= kUnpackError
;
933 const bool is_success
= error
== ComponentUnpacker::kNone
;
935 CrxUpdateItem
* item
= FindUpdateItemById(component_id
);
937 if (item
->state
== CrxUpdateItem::State::kUpdatingDiff
&& !is_success
) {
938 item
->diff_error_category
= error_category
;
939 item
->diff_error_code
= error
;
940 item
->diff_extra_code1
= extra_code
;
941 item
->diff_update_failed
= true;
942 size_t count
= ChangeItemStatus(CrxUpdateItem::State::kUpdatingDiff
,
943 CrxUpdateItem::State::kCanUpdate
);
944 DCHECK_EQ(count
, 1ul);
945 ScheduleNextRun(kStepDelayShort
);
950 item
->component
.version
= item
->next_version
;
951 item
->component
.fingerprint
= item
->next_fp
;
952 ChangeItemState(item
, CrxUpdateItem::State::kUpdated
);
954 item
->error_category
= error_category
;
955 item
->error_code
= error
;
956 item
->extra_code1
= extra_code
;
957 ChangeItemState(item
, CrxUpdateItem::State::kNoUpdate
);
960 ping_manager_
->OnUpdateComplete(item
);
962 // Move on to the next update, if there is one available.
963 ScheduleNextRun(kStepDelayMedium
);
966 void CrxUpdateService::NotifyObservers(Observer::Events event
,
967 const std::string
& id
) {
968 DCHECK(thread_checker_
.CalledOnValidThread());
969 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnEvent(event
, id
));
972 ComponentUpdateService::Status
CrxUpdateService::OnDemandUpdateWithCooldown(
973 CrxUpdateItem
* uit
) {
975 return Status::kError
;
977 // Check if the request is too soon.
978 base::TimeDelta delta
= base::Time::Now() - uit
->last_check
;
979 if (delta
< base::TimeDelta::FromSeconds(config_
->OnDemandDelay()))
980 return Status::kError
;
982 return OnDemandUpdateInternal(uit
);
985 ComponentUpdateService::Status
CrxUpdateService::OnDemandUpdateInternal(
986 CrxUpdateItem
* uit
) {
988 return Status::kError
;
990 uit
->on_demand
= true;
992 // If there is an update available for this item, then continue processing
993 // the update. This is an artifact of how update checks are done: in addition
994 // to the on-demand item, the update check may include other items as well.
995 if (uit
->state
!= CrxUpdateItem::State::kCanUpdate
) {
996 Status service_status
= GetServiceStatus(uit
->state
);
997 // If the item is already in the process of being updated, there is
998 // no point in this call, so return Status::kInProgress.
999 if (service_status
== Status::kInProgress
)
1000 return service_status
;
1002 // Otherwise the item was already checked a while back (or it is new),
1003 // set its state to kNew to give it a slightly higher priority.
1004 ChangeItemState(uit
, CrxUpdateItem::State::kNew
);
1007 // In case the current delay is long, set the timer to a shorter value
1008 // to get the ball rolling.
1009 if (timer_
.IsRunning()) {
1011 timer_
.Start(FROM_HERE
,
1012 base::TimeDelta::FromSeconds(config_
->StepDelay()),
1014 &CrxUpdateService::ProcessPendingItems
);
1020 ComponentUpdateService::Status
CrxUpdateService::GetServiceStatus(
1021 CrxUpdateItem::State state
) {
1023 case CrxUpdateItem::State::kChecking
:
1024 case CrxUpdateItem::State::kCanUpdate
:
1025 case CrxUpdateItem::State::kDownloadingDiff
:
1026 case CrxUpdateItem::State::kDownloading
:
1027 case CrxUpdateItem::State::kDownloaded
:
1028 case CrxUpdateItem::State::kUpdatingDiff
:
1029 case CrxUpdateItem::State::kUpdating
:
1030 return Status::kInProgress
;
1031 case CrxUpdateItem::State::kNew
:
1032 case CrxUpdateItem::State::kUpdated
:
1033 case CrxUpdateItem::State::kUpToDate
:
1034 case CrxUpdateItem::State::kNoUpdate
:
1036 case CrxUpdateItem::State::kLastStatus
:
1037 NOTREACHED() << static_cast<int>(state
);
1039 return Status::kError
;
1042 ///////////////////////////////////////////////////////////////////////////////
1044 // The component update factory. Using the component updater as a singleton
1045 // is the job of the browser process.
1046 scoped_ptr
<ComponentUpdateService
> ComponentUpdateServiceFactory(
1047 const scoped_refptr
<Configurator
>& config
) {
1049 return scoped_ptr
<ComponentUpdateService
>(new CrxUpdateService(config
));
1052 } // namespace component_updater