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/component_updater/component_patcher_operation.h"
29 #include "components/component_updater/component_unpacker.h"
30 #include "components/component_updater/component_updater_configurator.h"
31 #include "components/component_updater/component_updater_ping_manager.h"
32 #include "components/component_updater/component_updater_utils.h"
33 #include "components/component_updater/crx_downloader.h"
34 #include "components/component_updater/crx_update_item.h"
35 #include "components/component_updater/update_checker.h"
36 #include "components/component_updater/update_response.h"
39 namespace component_updater
{
41 // The component updater is designed to live until process shutdown, so
42 // base::Bind() calls are not refcounted.
46 // Returns true if the |proposed| version is newer than |current| version.
47 bool IsVersionNewer(const Version
& current
, const std::string
& proposed
) {
48 Version
proposed_ver(proposed
);
49 return proposed_ver
.IsValid() && current
.CompareTo(proposed_ver
) < 0;
52 // Returns true if a differential update is available, it has not failed yet,
53 // and the configuration allows it.
54 bool CanTryDiffUpdate(const CrxUpdateItem
* update_item
,
55 const Configurator
& config
) {
56 return HasDiffUpdate(update_item
) && !update_item
->diff_update_failed
&&
57 config
.DeltasEnabled();
60 void AppendDownloadMetrics(
61 const std::vector
<CrxDownloader::DownloadMetrics
>& source
,
62 std::vector
<CrxDownloader::DownloadMetrics
>* destination
) {
63 destination
->insert(destination
->end(), source
.begin(), source
.end());
68 CrxUpdateItem::CrxUpdateItem()
71 diff_update_failed(false),
75 diff_error_category(0),
80 CrxUpdateItem::~CrxUpdateItem() {
83 CrxComponent::CrxComponent()
84 : installer(NULL
), allow_background_download(true) {
87 CrxComponent::~CrxComponent() {
90 //////////////////////////////////////////////////////////////////////////////
91 // The one and only implementation of the ComponentUpdateService interface. In
92 // charge of running the show. The main method is ProcessPendingItems() which
93 // is called periodically to do the upgrades/installs or the update checks.
94 // An important consideration here is to be as "low impact" as we can to the
95 // rest of the browser, so even if we have many components registered and
96 // eligible for update, we only do one thing at a time with pauses in between
97 // the tasks. Also when we do network requests there is only one |url_fetcher_|
98 // in flight at a time.
99 // There are no locks in this code, the main structure |work_items_| is mutated
100 // only from the main thread. The unpack and installation is done in a blocking
101 // pool thread. The network requests are done in the IO thread or in the file
103 class CrxUpdateService
: public ComponentUpdateService
, public OnDemandUpdater
{
105 explicit CrxUpdateService(Configurator
* config
);
106 virtual ~CrxUpdateService();
108 // Overrides for ComponentUpdateService.
109 virtual void AddObserver(Observer
* observer
) override
;
110 virtual void RemoveObserver(Observer
* observer
) override
;
111 virtual Status
Start() override
;
112 virtual Status
Stop() override
;
113 virtual Status
RegisterComponent(const CrxComponent
& component
) override
;
114 virtual std::vector
<std::string
> GetComponentIDs() const override
;
115 virtual OnDemandUpdater
& GetOnDemandUpdater() override
;
116 virtual void MaybeThrottle(const std::string
& crx_id
,
117 const base::Closure
& callback
) override
;
118 virtual scoped_refptr
<base::SequencedTaskRunner
> GetSequencedTaskRunner()
121 // Context for a crx download url request.
123 ComponentInstaller
* installer
;
124 std::vector
<uint8_t> pk_hash
;
126 std::string fingerprint
;
127 CRXContext() : installer(NULL
) {}
138 enum StepDelayInterval
{
144 // Overrides for ComponentUpdateService.
145 virtual bool GetComponentDetails(const std::string
& component_id
,
146 CrxUpdateItem
* item
) const override
;
148 // Overrides for OnDemandUpdater.
149 virtual Status
OnDemandUpdate(const std::string
& component_id
) override
;
151 void UpdateCheckComplete(const GURL
& original_url
,
153 const std::string
& error_message
,
154 const UpdateResponse::Results
& results
);
155 void OnUpdateCheckSucceeded(const UpdateResponse::Results
& results
);
156 void OnUpdateCheckFailed(int error
, const std::string
& error_message
);
158 void DownloadProgress(const std::string
& component_id
,
159 const CrxDownloader::Result
& download_result
);
161 void DownloadComplete(scoped_ptr
<CRXContext
> crx_context
,
162 const CrxDownloader::Result
& download_result
);
164 Status
OnDemandUpdateInternal(CrxUpdateItem
* item
);
165 Status
OnDemandUpdateWithCooldown(CrxUpdateItem
* item
);
167 void ProcessPendingItems();
169 // Find a component that is ready to update.
170 CrxUpdateItem
* FindReadyComponent() const;
172 // Prepares the components for an update check and initiates the request.
173 // Returns true if an update check request has been made. Returns false if
174 // no update check was needed or an error occured.
175 bool CheckForUpdates();
177 void UpdateComponent(CrxUpdateItem
* workitem
);
179 void ScheduleNextRun(StepDelayInterval step_delay
);
181 void ParseResponse(const std::string
& xml
);
183 void Install(scoped_ptr
<CRXContext
> context
, const base::FilePath
& crx_path
);
185 void EndUnpacking(const std::string
& component_id
,
186 const base::FilePath
& crx_path
,
187 ComponentUnpacker::Error error
,
190 void DoneInstalling(const std::string
& component_id
,
191 ComponentUnpacker::Error error
,
194 void ChangeItemState(CrxUpdateItem
* item
, CrxUpdateItem::Status to
);
196 size_t ChangeItemStatus(CrxUpdateItem::Status from
, CrxUpdateItem::Status to
);
198 CrxUpdateItem
* FindUpdateItemById(const std::string
& id
) const;
200 void NotifyObservers(Observer::Events event
, const std::string
& id
);
202 bool HasOnDemandItems() const;
204 Status
GetServiceStatus(const CrxUpdateItem::Status status
);
206 scoped_ptr
<Configurator
> config_
;
208 scoped_ptr
<UpdateChecker
> update_checker_
;
210 scoped_ptr
<PingManager
> ping_manager_
;
212 scoped_refptr
<ComponentUnpacker
> unpacker_
;
214 scoped_ptr
<CrxDownloader
> crx_downloader_
;
216 // A collection of every work item.
217 typedef std::vector
<CrxUpdateItem
*> UpdateItems
;
218 UpdateItems work_items_
;
220 base::OneShotTimer
<CrxUpdateService
> timer_
;
222 base::ThreadChecker thread_checker_
;
224 // Used to post responses back to the main thread.
225 scoped_refptr
<base::SingleThreadTaskRunner
> main_task_runner_
;
227 scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner_
;
231 ObserverList
<Observer
> observer_list_
;
233 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService
);
236 //////////////////////////////////////////////////////////////////////////////
238 CrxUpdateService::CrxUpdateService(Configurator
* config
)
240 ping_manager_(new PingManager(*config
)),
241 main_task_runner_(base::MessageLoopProxy::current()),
242 blocking_task_runner_(config
->GetSequencedTaskRunner()),
246 CrxUpdateService::~CrxUpdateService() {
247 // Because we are a singleton, at this point only the main thread should be
248 // alive, this simplifies the management of the work that could be in
249 // flight in other threads.
251 STLDeleteElements(&work_items_
);
254 void CrxUpdateService::AddObserver(Observer
* observer
) {
255 DCHECK(thread_checker_
.CalledOnValidThread());
256 observer_list_
.AddObserver(observer
);
259 void CrxUpdateService::RemoveObserver(Observer
* observer
) {
260 DCHECK(thread_checker_
.CalledOnValidThread());
261 observer_list_
.RemoveObserver(observer
);
264 ComponentUpdateService::Status
CrxUpdateService::Start() {
265 // Note that RegisterComponent will call Start() when the first
266 // component is registered, so it can be called twice. This way
267 // we avoid scheduling the timer if there is no work to do.
268 VLOG(1) << "CrxUpdateService starting up";
270 if (work_items_
.empty())
273 NotifyObservers(Observer::COMPONENT_UPDATER_STARTED
, "");
275 VLOG(1) << "First update attempt will take place in "
276 << config_
->InitialDelay() << " seconds";
277 timer_
.Start(FROM_HERE
,
278 base::TimeDelta::FromSeconds(config_
->InitialDelay()),
280 &CrxUpdateService::ProcessPendingItems
);
284 // Stop the main check + update loop. In flight operations will be
286 ComponentUpdateService::Status
CrxUpdateService::Stop() {
287 VLOG(1) << "CrxUpdateService stopping";
293 bool CrxUpdateService::HasOnDemandItems() const {
296 static bool IsOnDemand(CrxUpdateItem
* item
) { return item
->on_demand
; }
298 return std::find_if(work_items_
.begin(),
300 Helper::IsOnDemand
) != work_items_
.end();
303 // This function sets the timer which will call ProcessPendingItems() or
304 // ProcessRequestedItem() if there is an on_demand item. There
305 // are three kinds of waits:
306 // - a short delay, when there is immediate work to be done.
307 // - a medium delay, when there are updates to be applied within the current
308 // update cycle, or there are components that are still unchecked.
309 // - a long delay when a full check/update cycle has completed for all
311 void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay
) {
312 DCHECK(thread_checker_
.CalledOnValidThread());
313 DCHECK(!update_checker_
);
314 CHECK(!timer_
.IsRunning());
315 // It could be the case that Stop() had been called while a url request
316 // or unpacking was in flight, if so we arrive here but |running_| is
317 // false. In that case do not loop again.
321 // Keep the delay short if in the middle of an update (step_delay),
322 // or there are new requested_work_items_ that have not been processed yet.
323 int64_t delay_seconds
= 0;
324 if (!HasOnDemandItems()) {
325 switch (step_delay
) {
326 case kStepDelayShort
:
327 delay_seconds
= config_
->StepDelay();
329 case kStepDelayMedium
:
330 delay_seconds
= config_
->StepDelayMedium();
333 delay_seconds
= config_
->NextCheckDelay();
337 delay_seconds
= config_
->StepDelay();
340 if (step_delay
!= kStepDelayShort
) {
341 NotifyObservers(Observer::COMPONENT_UPDATER_SLEEPING
, "");
343 // Zero is only used for unit tests.
344 if (0 == delay_seconds
)
348 VLOG(1) << "Scheduling next run to occur in " << delay_seconds
<< " seconds";
349 timer_
.Start(FROM_HERE
,
350 base::TimeDelta::FromSeconds(delay_seconds
),
352 &CrxUpdateService::ProcessPendingItems
);
355 // Given a extension-like component id, find the associated component.
356 CrxUpdateItem
* CrxUpdateService::FindUpdateItemById(
357 const std::string
& id
) const {
358 DCHECK(thread_checker_
.CalledOnValidThread());
359 CrxUpdateItem::FindById
finder(id
);
360 UpdateItems::const_iterator it
=
361 std::find_if(work_items_
.begin(), work_items_
.end(), finder
);
362 return it
!= work_items_
.end() ? *it
: NULL
;
365 // Changes a component's status, clearing on_demand and firing notifications as
366 // necessary. By convention, this is the only function that can change a
367 // CrxUpdateItem's |status|.
368 // TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
369 void CrxUpdateService::ChangeItemState(CrxUpdateItem
* item
,
370 CrxUpdateItem::Status to
) {
371 DCHECK(thread_checker_
.CalledOnValidThread());
372 if (to
== CrxUpdateItem::kNoUpdate
|| to
== CrxUpdateItem::kUpdated
||
373 to
== CrxUpdateItem::kUpToDate
) {
374 item
->on_demand
= false;
380 case CrxUpdateItem::kCanUpdate
:
381 NotifyObservers(Observer::COMPONENT_UPDATE_FOUND
, item
->id
);
383 case CrxUpdateItem::kUpdatingDiff
:
384 case CrxUpdateItem::kUpdating
:
385 NotifyObservers(Observer::COMPONENT_UPDATE_READY
, item
->id
);
387 case CrxUpdateItem::kUpdated
:
388 NotifyObservers(Observer::COMPONENT_UPDATED
, item
->id
);
390 case CrxUpdateItem::kUpToDate
:
391 case CrxUpdateItem::kNoUpdate
:
392 NotifyObservers(Observer::COMPONENT_NOT_UPDATED
, item
->id
);
394 case CrxUpdateItem::kNew
:
395 case CrxUpdateItem::kChecking
:
396 case CrxUpdateItem::kDownloading
:
397 case CrxUpdateItem::kDownloadingDiff
:
398 case CrxUpdateItem::kLastStatus
:
399 // No notification for these states.
403 // Free possible pending network requests.
404 if ((to
== CrxUpdateItem::kUpdated
) || (to
== CrxUpdateItem::kUpToDate
) ||
405 (to
== CrxUpdateItem::kNoUpdate
)) {
406 for (std::vector
<base::Closure
>::iterator it
=
407 item
->ready_callbacks
.begin();
408 it
!= item
->ready_callbacks
.end();
412 item
->ready_callbacks
.clear();
416 // Changes all the components in |work_items_| that have |from| status to
417 // |to| status and returns how many have been changed.
418 size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from
,
419 CrxUpdateItem::Status to
) {
420 DCHECK(thread_checker_
.CalledOnValidThread());
422 for (UpdateItems::iterator it
= work_items_
.begin();
423 it
!= work_items_
.end();
425 CrxUpdateItem
* item
= *it
;
426 if (item
->status
== from
) {
427 ChangeItemState(item
, to
);
434 // Adds a component to be checked for upgrades. If the component exists it
435 // it will be replaced and the return code is kReplaced.
436 ComponentUpdateService::Status
CrxUpdateService::RegisterComponent(
437 const CrxComponent
& component
) {
438 DCHECK(thread_checker_
.CalledOnValidThread());
439 if (component
.pk_hash
.empty() || !component
.version
.IsValid() ||
440 !component
.installer
)
443 std::string
id(GetCrxComponentID(component
));
444 CrxUpdateItem
* uit
= FindUpdateItemById(id
);
446 uit
->component
= component
;
450 uit
= new CrxUpdateItem
;
452 uit
->component
= component
;
454 work_items_
.push_back(uit
);
456 // If this is the first component registered we call Start to
457 // schedule the first timer. Otherwise, reset the timer to trigger another
458 // pass over the work items, if the component updater is sleeping, fact
459 // indicated by a running timer. If the timer is not running, it means that
460 // the service is busy updating something, and in that case, this component
461 // will be picked up at the next pass.
463 if (work_items_
.size() == 1) {
465 } else if (timer_
.IsRunning()) {
466 timer_
.Start(FROM_HERE
,
467 base::TimeDelta::FromSeconds(config_
->InitialDelay()),
469 &CrxUpdateService::ProcessPendingItems
);
476 std::vector
<std::string
> CrxUpdateService::GetComponentIDs() const {
477 DCHECK(thread_checker_
.CalledOnValidThread());
478 std::vector
<std::string
> component_ids
;
479 for (UpdateItems::const_iterator it
= work_items_
.begin();
480 it
!= work_items_
.end();
482 const CrxUpdateItem
* item
= *it
;
483 component_ids
.push_back(item
->id
);
485 return component_ids
;
488 OnDemandUpdater
& CrxUpdateService::GetOnDemandUpdater() {
492 void CrxUpdateService::MaybeThrottle(const std::string
& crx_id
,
493 const base::Closure
& callback
) {
494 DCHECK(thread_checker_
.CalledOnValidThread());
495 // Check if we can on-demand update, else unblock the request anyway.
496 CrxUpdateItem
* item
= FindUpdateItemById(crx_id
);
497 Status status
= OnDemandUpdateWithCooldown(item
);
498 if (status
== kOk
|| status
== kInProgress
) {
499 item
->ready_callbacks
.push_back(callback
);
505 scoped_refptr
<base::SequencedTaskRunner
>
506 CrxUpdateService::GetSequencedTaskRunner() {
507 return config_
->GetSequencedTaskRunner();
510 bool CrxUpdateService::GetComponentDetails(const std::string
& component_id
,
511 CrxUpdateItem
* item
) const {
512 DCHECK(thread_checker_
.CalledOnValidThread());
513 const CrxUpdateItem
* crx_update_item(FindUpdateItemById(component_id
));
515 *item
= *crx_update_item
;
516 return crx_update_item
!= NULL
;
519 // Start the process of checking for an update, for a particular component
520 // that was previously registered.
521 // |component_id| is a value returned from GetCrxComponentID().
522 ComponentUpdateService::Status
CrxUpdateService::OnDemandUpdate(
523 const std::string
& component_id
) {
524 return OnDemandUpdateInternal(FindUpdateItemById(component_id
));
527 // This is the main loop of the component updater. It updates one component
528 // at a time if updates are available. Otherwise, it does an update check or
529 // takes a long sleep until the loop runs again.
530 void CrxUpdateService::ProcessPendingItems() {
531 DCHECK(thread_checker_
.CalledOnValidThread());
533 CrxUpdateItem
* ready_upgrade
= FindReadyComponent();
535 UpdateComponent(ready_upgrade
);
539 if (!CheckForUpdates())
540 ScheduleNextRun(kStepDelayLong
);
543 CrxUpdateItem
* CrxUpdateService::FindReadyComponent() const {
546 static bool IsReadyOnDemand(CrxUpdateItem
* item
) {
547 return item
->on_demand
&& IsReady(item
);
549 static bool IsReady(CrxUpdateItem
* item
) {
550 return item
->status
== CrxUpdateItem::kCanUpdate
;
554 std::vector
<CrxUpdateItem
*>::const_iterator it
= std::find_if(
555 work_items_
.begin(), work_items_
.end(), Helper::IsReadyOnDemand
);
556 if (it
!= work_items_
.end())
558 it
= std::find_if(work_items_
.begin(), work_items_
.end(), Helper::IsReady
);
559 if (it
!= work_items_
.end())
564 // Prepares the components for an update check and initiates the request.
565 // On demand components are always included in the update check request.
566 // Otherwise, only include components that have not been checked recently.
567 bool CrxUpdateService::CheckForUpdates() {
568 const base::TimeDelta minimum_recheck_wait_time
=
569 base::TimeDelta::FromSeconds(config_
->MinimumReCheckWait());
570 const base::Time
now(base::Time::Now());
572 std::vector
<CrxUpdateItem
*> items_to_check
;
573 for (size_t i
= 0; i
!= work_items_
.size(); ++i
) {
574 CrxUpdateItem
* item
= work_items_
[i
];
575 DCHECK(item
->status
== CrxUpdateItem::kNew
||
576 item
->status
== CrxUpdateItem::kNoUpdate
||
577 item
->status
== CrxUpdateItem::kUpToDate
||
578 item
->status
== CrxUpdateItem::kUpdated
);
580 const base::TimeDelta
time_since_last_checked(now
- item
->last_check
);
582 if (!item
->on_demand
&&
583 time_since_last_checked
< minimum_recheck_wait_time
) {
584 VLOG(1) << "Skipping check for component update: id=" << item
->id
585 << ", time_since_last_checked="
586 << time_since_last_checked
.InSeconds()
587 << " seconds: too soon to check for an update";
591 VLOG(1) << "Scheduling update check for component id=" << item
->id
592 << ", time_since_last_checked="
593 << time_since_last_checked
.InSeconds() << " seconds";
595 item
->last_check
= now
;
596 item
->crx_urls
.clear();
597 item
->crx_diffurls
.clear();
598 item
->previous_version
= item
->component
.version
;
599 item
->next_version
= Version();
600 item
->previous_fp
= item
->component
.fingerprint
;
601 item
->next_fp
.clear();
602 item
->diff_update_failed
= false;
603 item
->error_category
= 0;
604 item
->error_code
= 0;
605 item
->extra_code1
= 0;
606 item
->diff_error_category
= 0;
607 item
->diff_error_code
= 0;
608 item
->diff_extra_code1
= 0;
609 item
->download_metrics
.clear();
611 items_to_check
.push_back(item
);
613 ChangeItemState(item
, CrxUpdateItem::kChecking
);
616 if (items_to_check
.empty())
619 update_checker_
= UpdateChecker::Create(*config_
).Pass();
620 return update_checker_
->CheckForUpdates(
622 config_
->ExtraRequestParams(),
623 base::Bind(&CrxUpdateService::UpdateCheckComplete
,
624 base::Unretained(this)));
627 void CrxUpdateService::UpdateComponent(CrxUpdateItem
* workitem
) {
628 scoped_ptr
<CRXContext
> crx_context(new CRXContext
);
629 crx_context
->pk_hash
= workitem
->component
.pk_hash
;
630 crx_context
->id
= workitem
->id
;
631 crx_context
->installer
= workitem
->component
.installer
;
632 crx_context
->fingerprint
= workitem
->next_fp
;
633 const std::vector
<GURL
>* urls
= NULL
;
634 bool allow_background_download
= false;
635 if (CanTryDiffUpdate(workitem
, *config_
)) {
636 urls
= &workitem
->crx_diffurls
;
637 ChangeItemState(workitem
, CrxUpdateItem::kDownloadingDiff
);
639 // Background downloads are enabled only for selected components and
640 // only for full downloads (see issue 340448).
641 allow_background_download
= workitem
->component
.allow_background_download
;
642 urls
= &workitem
->crx_urls
;
643 ChangeItemState(workitem
, CrxUpdateItem::kDownloading
);
646 // On demand component updates are always downloaded in foreground.
647 const bool is_background_download
= !workitem
->on_demand
&&
648 allow_background_download
&&
649 config_
->UseBackgroundDownloader();
651 crx_downloader_
.reset(
652 CrxDownloader::Create(is_background_download
,
653 config_
->RequestContext(),
654 blocking_task_runner_
,
655 config_
->GetSingleThreadTaskRunner()));
656 crx_downloader_
->set_progress_callback(
657 base::Bind(&CrxUpdateService::DownloadProgress
,
658 base::Unretained(this),
660 crx_downloader_
->StartDownload(*urls
,
661 base::Bind(&CrxUpdateService::DownloadComplete
,
662 base::Unretained(this),
663 base::Passed(&crx_context
)));
666 void CrxUpdateService::UpdateCheckComplete(
667 const GURL
& original_url
,
669 const std::string
& error_message
,
670 const UpdateResponse::Results
& results
) {
671 DCHECK(thread_checker_
.CalledOnValidThread());
672 VLOG(1) << "Update check completed from: " << original_url
.spec();
673 update_checker_
.reset();
675 OnUpdateCheckSucceeded(results
);
677 OnUpdateCheckFailed(error
, error_message
);
680 // Handles a valid Omaha update check response by matching the results with
681 // the registered components which were checked for updates.
682 // If updates are found, prepare the components for the actual version upgrade.
683 // One of these components will be drafted for the upgrade next time
684 // ProcessPendingItems is called.
685 void CrxUpdateService::OnUpdateCheckSucceeded(
686 const UpdateResponse::Results
& results
) {
687 size_t num_updates_pending
= 0;
688 DCHECK(thread_checker_
.CalledOnValidThread());
689 VLOG(1) << "Update check succeeded.";
690 std::vector
<UpdateResponse::Result
>::const_iterator it
;
691 for (it
= results
.list
.begin(); it
!= results
.list
.end(); ++it
) {
692 CrxUpdateItem
* crx
= FindUpdateItemById(it
->extension_id
);
696 if (crx
->status
!= CrxUpdateItem::kChecking
) {
698 continue; // Not updating this component now.
701 if (it
->manifest
.version
.empty()) {
702 // No version means no update available.
703 ChangeItemState(crx
, CrxUpdateItem::kNoUpdate
);
704 VLOG(1) << "No update available for component: " << crx
->id
;
708 if (!IsVersionNewer(crx
->component
.version
, it
->manifest
.version
)) {
709 // The component is up to date.
710 ChangeItemState(crx
, CrxUpdateItem::kUpToDate
);
711 VLOG(1) << "Component already up-to-date: " << crx
->id
;
715 if (!it
->manifest
.browser_min_version
.empty()) {
716 if (IsVersionNewer(config_
->GetBrowserVersion(),
717 it
->manifest
.browser_min_version
)) {
718 // The component is not compatible with this Chrome version.
719 VLOG(1) << "Ignoring incompatible component: " << crx
->id
;
720 ChangeItemState(crx
, CrxUpdateItem::kNoUpdate
);
725 if (it
->manifest
.packages
.size() != 1) {
726 // Assume one and only one package per component.
727 VLOG(1) << "Ignoring multiple packages for component: " << crx
->id
;
728 ChangeItemState(crx
, CrxUpdateItem::kNoUpdate
);
732 // Parse the members of the result and queue an upgrade for this component.
733 crx
->next_version
= Version(it
->manifest
.version
);
735 VLOG(1) << "Update found for component: " << crx
->id
;
737 typedef UpdateResponse::Result::Manifest::Package Package
;
738 const Package
& package(it
->manifest
.packages
[0]);
739 crx
->next_fp
= package
.fingerprint
;
741 // Resolve the urls by combining the base urls with the package names.
742 for (size_t i
= 0; i
!= it
->crx_urls
.size(); ++i
) {
743 const GURL
url(it
->crx_urls
[i
].Resolve(package
.name
));
745 crx
->crx_urls
.push_back(url
);
747 for (size_t i
= 0; i
!= it
->crx_diffurls
.size(); ++i
) {
748 const GURL
url(it
->crx_diffurls
[i
].Resolve(package
.namediff
));
750 crx
->crx_diffurls
.push_back(url
);
753 ChangeItemState(crx
, CrxUpdateItem::kCanUpdate
);
754 ++num_updates_pending
;
757 // All components that are not included in the update response are
758 // considered up to date.
759 ChangeItemStatus(CrxUpdateItem::kChecking
, CrxUpdateItem::kUpToDate
);
761 // If there are updates pending we do a short wait, otherwise we take
762 // a longer delay until we check the components again.
763 ScheduleNextRun(num_updates_pending
> 0 ? kStepDelayShort
: kStepDelayLong
);
766 void CrxUpdateService::OnUpdateCheckFailed(int error
,
767 const std::string
& error_message
) {
768 DCHECK(thread_checker_
.CalledOnValidThread());
771 ChangeItemStatus(CrxUpdateItem::kChecking
, CrxUpdateItem::kNoUpdate
);
772 DCHECK_GT(count
, 0ul);
773 VLOG(1) << "Update check failed.";
774 ScheduleNextRun(kStepDelayLong
);
777 // Called when progress is being made downloading a CRX. The progress may
778 // not monotonically increase due to how the CRX downloader switches between
779 // different downloaders and fallback urls.
780 void CrxUpdateService::DownloadProgress(
781 const std::string
& component_id
,
782 const CrxDownloader::Result
& download_result
) {
783 DCHECK(thread_checker_
.CalledOnValidThread());
784 NotifyObservers(Observer::COMPONENT_UPDATE_DOWNLOADING
, component_id
);
787 // Called when the CRX package has been downloaded to a temporary location.
788 // Here we fire the notifications and schedule the component-specific installer
789 // to be called in the file thread.
790 void CrxUpdateService::DownloadComplete(
791 scoped_ptr
<CRXContext
> crx_context
,
792 const CrxDownloader::Result
& download_result
) {
793 DCHECK(thread_checker_
.CalledOnValidThread());
795 CrxUpdateItem
* crx
= FindUpdateItemById(crx_context
->id
);
796 DCHECK(crx
->status
== CrxUpdateItem::kDownloadingDiff
||
797 crx
->status
== CrxUpdateItem::kDownloading
);
799 AppendDownloadMetrics(crx_downloader_
->download_metrics(),
800 &crx
->download_metrics
);
802 crx_downloader_
.reset();
804 if (download_result
.error
) {
805 if (crx
->status
== CrxUpdateItem::kDownloadingDiff
) {
806 crx
->diff_error_category
= kNetworkError
;
807 crx
->diff_error_code
= download_result
.error
;
808 crx
->diff_update_failed
= true;
809 size_t count
= ChangeItemStatus(CrxUpdateItem::kDownloadingDiff
,
810 CrxUpdateItem::kCanUpdate
);
811 DCHECK_EQ(count
, 1ul);
813 ScheduleNextRun(kStepDelayShort
);
816 crx
->error_category
= kNetworkError
;
817 crx
->error_code
= download_result
.error
;
819 ChangeItemStatus(CrxUpdateItem::kDownloading
, CrxUpdateItem::kNoUpdate
);
820 DCHECK_EQ(count
, 1ul);
822 // At this point, since both the differential and the full downloads failed,
823 // the update for this component has finished with an error.
824 ping_manager_
->OnUpdateComplete(crx
);
826 // Move on to the next update, if there is one available.
827 ScheduleNextRun(kStepDelayMedium
);
830 if (crx
->status
== CrxUpdateItem::kDownloadingDiff
) {
831 count
= ChangeItemStatus(CrxUpdateItem::kDownloadingDiff
,
832 CrxUpdateItem::kUpdatingDiff
);
834 count
= ChangeItemStatus(CrxUpdateItem::kDownloading
,
835 CrxUpdateItem::kUpdating
);
837 DCHECK_EQ(count
, 1ul);
839 // Why unretained? See comment at top of file.
840 blocking_task_runner_
->PostDelayedTask(
842 base::Bind(&CrxUpdateService::Install
,
843 base::Unretained(this),
844 base::Passed(&crx_context
),
845 download_result
.response
),
846 base::TimeDelta::FromMilliseconds(config_
->StepDelay()));
850 // Install consists of digital signature verification, unpacking and then
851 // calling the component specific installer. All that is handled by the
852 // |unpacker_|. If there is an error this function is in charge of deleting
853 // the files created.
854 void CrxUpdateService::Install(scoped_ptr
<CRXContext
> context
,
855 const base::FilePath
& crx_path
) {
856 // This function owns the file at |crx_path| and the |context| object.
857 unpacker_
= new ComponentUnpacker(context
->pk_hash
,
859 context
->fingerprint
,
861 config_
->CreateOutOfProcessPatcher(),
862 blocking_task_runner_
);
863 unpacker_
->Unpack(base::Bind(&CrxUpdateService::EndUnpacking
,
864 base::Unretained(this),
869 void CrxUpdateService::EndUnpacking(const std::string
& component_id
,
870 const base::FilePath
& crx_path
,
871 ComponentUnpacker::Error error
,
872 int extended_error
) {
873 if (!DeleteFileAndEmptyParentDirectory(crx_path
))
874 NOTREACHED() << crx_path
.value();
875 main_task_runner_
->PostDelayedTask(
877 base::Bind(&CrxUpdateService::DoneInstalling
,
878 base::Unretained(this),
882 base::TimeDelta::FromMilliseconds(config_
->StepDelay()));
883 // Reset the unpacker last, otherwise we free our own arguments.
887 // Installation has been completed. Adjust the component status and
888 // schedule the next check. Schedule a short delay before trying the full
889 // update when the differential update failed.
890 void CrxUpdateService::DoneInstalling(const std::string
& component_id
,
891 ComponentUnpacker::Error error
,
893 DCHECK(thread_checker_
.CalledOnValidThread());
895 ErrorCategory error_category
= kErrorNone
;
897 case ComponentUnpacker::kNone
:
899 case ComponentUnpacker::kInstallerError
:
900 error_category
= kInstallError
;
903 error_category
= kUnpackError
;
907 const bool is_success
= error
== ComponentUnpacker::kNone
;
909 CrxUpdateItem
* item
= FindUpdateItemById(component_id
);
910 if (item
->status
== CrxUpdateItem::kUpdatingDiff
&& !is_success
) {
911 item
->diff_error_category
= error_category
;
912 item
->diff_error_code
= error
;
913 item
->diff_extra_code1
= extra_code
;
914 item
->diff_update_failed
= true;
915 size_t count
= ChangeItemStatus(CrxUpdateItem::kUpdatingDiff
,
916 CrxUpdateItem::kCanUpdate
);
917 DCHECK_EQ(count
, 1ul);
918 ScheduleNextRun(kStepDelayShort
);
923 item
->component
.version
= item
->next_version
;
924 item
->component
.fingerprint
= item
->next_fp
;
925 ChangeItemState(item
, CrxUpdateItem::kUpdated
);
927 item
->error_category
= error_category
;
928 item
->error_code
= error
;
929 item
->extra_code1
= extra_code
;
930 ChangeItemState(item
, CrxUpdateItem::kNoUpdate
);
933 ping_manager_
->OnUpdateComplete(item
);
935 // Move on to the next update, if there is one available.
936 ScheduleNextRun(kStepDelayMedium
);
939 void CrxUpdateService::NotifyObservers(Observer::Events event
,
940 const std::string
& id
) {
941 DCHECK(thread_checker_
.CalledOnValidThread());
942 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnEvent(event
, id
));
945 ComponentUpdateService::Status
CrxUpdateService::OnDemandUpdateWithCooldown(
946 CrxUpdateItem
* uit
) {
950 // Check if the request is too soon.
951 base::TimeDelta delta
= base::Time::Now() - uit
->last_check
;
952 if (delta
< base::TimeDelta::FromSeconds(config_
->OnDemandDelay()))
955 return OnDemandUpdateInternal(uit
);
958 ComponentUpdateService::Status
CrxUpdateService::OnDemandUpdateInternal(
959 CrxUpdateItem
* uit
) {
963 uit
->on_demand
= true;
965 // If there is an update available for this item, then continue processing
966 // the update. This is an artifact of how update checks are done: in addition
967 // to the on-demand item, the update check may include other items as well.
968 if (uit
->status
!= CrxUpdateItem::kCanUpdate
) {
969 Status service_status
= GetServiceStatus(uit
->status
);
970 // If the item is already in the process of being updated, there is
971 // no point in this call, so return kInProgress.
972 if (service_status
== kInProgress
)
973 return service_status
;
975 // Otherwise the item was already checked a while back (or it is new),
976 // set its status to kNew to give it a slightly higher priority.
977 ChangeItemState(uit
, CrxUpdateItem::kNew
);
980 // In case the current delay is long, set the timer to a shorter value
981 // to get the ball rolling.
982 if (timer_
.IsRunning()) {
984 timer_
.Start(FROM_HERE
,
985 base::TimeDelta::FromSeconds(config_
->StepDelay()),
987 &CrxUpdateService::ProcessPendingItems
);
993 ComponentUpdateService::Status
CrxUpdateService::GetServiceStatus(
994 CrxUpdateItem::Status status
) {
996 case CrxUpdateItem::kChecking
:
997 case CrxUpdateItem::kCanUpdate
:
998 case CrxUpdateItem::kDownloadingDiff
:
999 case CrxUpdateItem::kDownloading
:
1000 case CrxUpdateItem::kUpdatingDiff
:
1001 case CrxUpdateItem::kUpdating
:
1003 case CrxUpdateItem::kNew
:
1004 case CrxUpdateItem::kUpdated
:
1005 case CrxUpdateItem::kUpToDate
:
1006 case CrxUpdateItem::kNoUpdate
:
1008 case CrxUpdateItem::kLastStatus
:
1009 NOTREACHED() << status
;
1014 ///////////////////////////////////////////////////////////////////////////////
1016 // The component update factory. Using the component updater as a singleton
1017 // is the job of the browser process.
1018 ComponentUpdateService
* ComponentUpdateServiceFactory(Configurator
* config
) {
1020 return new CrxUpdateService(config
);
1023 } // namespace component_updater