1 // Copyright 2012 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 "chrome/browser/component_updater/component_updater_service.h"
11 #include "base/at_exit.h"
12 #include "base/bind.h"
13 #include "base/compiler_specific.h"
14 #include "base/file_util.h"
15 #include "base/files/file_path.h"
16 #include "base/logging.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/weak_ptr.h"
19 #include "base/observer_list.h"
20 #include "base/sequenced_task_runner.h"
21 #include "base/stl_util.h"
22 #include "base/threading/sequenced_worker_pool.h"
23 #include "base/timer/timer.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/component_updater/component_unpacker.h"
26 #include "chrome/browser/component_updater/component_updater_ping_manager.h"
27 #include "chrome/browser/component_updater/component_updater_utils.h"
28 #include "chrome/browser/component_updater/crx_downloader.h"
29 #include "chrome/browser/component_updater/crx_update_item.h"
30 #include "chrome/browser/component_updater/update_checker.h"
31 #include "chrome/browser/component_updater/update_response.h"
32 #include "chrome/common/chrome_version_info.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/resource_controller.h"
35 #include "content/public/browser/resource_throttle.h"
38 using content::BrowserThread
;
40 namespace component_updater
{
42 // The component updater is designed to live until process shutdown, so
43 // base::Bind() calls are not refcounted.
47 // Returns true if the |proposed| version is newer than |current| version.
48 bool IsVersionNewer(const Version
& current
, const std::string
& proposed
) {
49 Version
proposed_ver(proposed
);
50 return proposed_ver
.IsValid() && current
.CompareTo(proposed_ver
) < 0;
53 // Returns true if a differential update is available, it has not failed yet,
54 // and the configuration allows it.
55 bool CanTryDiffUpdate(const CrxUpdateItem
* update_item
,
56 const ComponentUpdateService::Configurator
& config
) {
57 return HasDiffUpdate(update_item
) &&
58 !update_item
->diff_update_failed
&&
59 config
.DeltasEnabled();
62 void AppendDownloadMetrics(
63 const std::vector
<CrxDownloader::DownloadMetrics
>& source
,
64 std::vector
<CrxDownloader::DownloadMetrics
>* destination
) {
65 destination
->insert(destination
->end(), source
.begin(), source
.end());
70 CrxUpdateItem::CrxUpdateItem()
73 diff_update_failed(false),
77 diff_error_category(0),
82 CrxUpdateItem::~CrxUpdateItem() {
85 CrxComponent::CrxComponent()
87 allow_background_download(true) {
90 CrxComponent::~CrxComponent() {
93 CrxComponentInfo::CrxComponentInfo() {
96 CrxComponentInfo::~CrxComponentInfo() {
99 ///////////////////////////////////////////////////////////////////////////////
100 // In charge of blocking url requests until the |crx_id| component has been
101 // updated. This class is touched solely from the IO thread. The UI thread
102 // can post tasks to it via weak pointers. By default the request is blocked
103 // unless the CrxUpdateService calls Unblock().
104 // The lifetime is controlled by Chrome's resource loader so the component
105 // updater cannot touch objects from this class except via weak pointers.
106 class CUResourceThrottle
107 : public content::ResourceThrottle
,
108 public base::SupportsWeakPtr
<CUResourceThrottle
> {
110 explicit CUResourceThrottle(const net::URLRequest
* request
);
111 virtual ~CUResourceThrottle();
113 // Overriden from ResourceThrottle.
114 virtual void WillStartRequest(bool* defer
) OVERRIDE
;
115 virtual void WillRedirectRequest(const GURL
& new_url
, bool* defer
) OVERRIDE
;
116 virtual const char* GetNameForLogging() const OVERRIDE
;
118 // Component updater calls this function via PostTask to unblock the request.
121 typedef std::vector
<base::WeakPtr
<CUResourceThrottle
> > WeakPtrVector
;
133 void UnblockResourceThrottle(base::WeakPtr
<CUResourceThrottle
> rt
) {
134 BrowserThread::PostTask(
137 base::Bind(&CUResourceThrottle::Unblock
, rt
));
140 void UnblockandReapAllThrottles(CUResourceThrottle::WeakPtrVector
* throttles
) {
141 CUResourceThrottle::WeakPtrVector::iterator it
;
142 for (it
= throttles
->begin(); it
!= throttles
->end(); ++it
)
143 UnblockResourceThrottle(*it
);
147 //////////////////////////////////////////////////////////////////////////////
148 // The one and only implementation of the ComponentUpdateService interface. In
149 // charge of running the show. The main method is ProcessPendingItems() which
150 // is called periodically to do the upgrades/installs or the update checks.
151 // An important consideration here is to be as "low impact" as we can to the
152 // rest of the browser, so even if we have many components registered and
153 // eligible for update, we only do one thing at a time with pauses in between
154 // the tasks. Also when we do network requests there is only one |url_fetcher_|
155 // in flight at a time.
156 // There are no locks in this code, the main structure |work_items_| is mutated
157 // only from the UI thread. The unpack and installation is done in a blocking
158 // pool thread. The network requests are done in the IO thread or in the file
160 class CrxUpdateService
: public ComponentUpdateService
{
162 explicit CrxUpdateService(ComponentUpdateService::Configurator
* config
);
163 virtual ~CrxUpdateService();
165 // Overrides for ComponentUpdateService.
166 virtual void AddObserver(Observer
* observer
) OVERRIDE
;
167 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
;
168 virtual Status
Start() OVERRIDE
;
169 virtual Status
Stop() OVERRIDE
;
170 virtual Status
RegisterComponent(const CrxComponent
& component
) OVERRIDE
;
171 virtual Status
OnDemandUpdate(const std::string
& component_id
) OVERRIDE
;
172 virtual void GetComponents(
173 std::vector
<CrxComponentInfo
>* components
) OVERRIDE
;
174 virtual content::ResourceThrottle
* GetOnDemandResourceThrottle(
175 net::URLRequest
* request
, const std::string
& crx_id
) OVERRIDE
;
177 // Context for a crx download url request.
179 ComponentInstaller
* installer
;
180 std::vector
<uint8
> pk_hash
;
182 std::string fingerprint
;
183 CRXContext() : installer(NULL
) {}
194 enum StepDelayInterval
{
200 void UpdateCheckComplete(int error
,
201 const std::string
& error_message
,
202 const UpdateResponse::Results
& results
);
203 void OnUpdateCheckSucceeded(const UpdateResponse::Results
& results
);
204 void OnUpdateCheckFailed(int error
, const std::string
& error_message
);
206 void DownloadComplete(
207 scoped_ptr
<CRXContext
> crx_context
,
208 const CrxDownloader::Result
& download_result
);
210 Status
OnDemandUpdateInternal(CrxUpdateItem
* item
);
212 void ProcessPendingItems();
214 // Find a component that is ready to update.
215 CrxUpdateItem
* FindReadyComponent() const;
217 // Prepares the components for an update check and initiates the request.
218 // Returns true if an update check request has been made. Returns false if
219 // no update check was needed or an error occured.
220 bool CheckForUpdates();
222 void UpdateComponent(CrxUpdateItem
* workitem
);
224 void ScheduleNextRun(StepDelayInterval step_delay
);
226 void ParseResponse(const std::string
& xml
);
228 void Install(scoped_ptr
<CRXContext
> context
, const base::FilePath
& crx_path
);
230 void EndUnpacking(const std::string
& component_id
,
231 const base::FilePath
& crx_path
,
232 ComponentUnpacker::Error error
,
235 void DoneInstalling(const std::string
& component_id
,
236 ComponentUnpacker::Error error
,
239 void ChangeItemState(CrxUpdateItem
* item
, CrxUpdateItem::Status to
);
241 size_t ChangeItemStatus(CrxUpdateItem::Status from
,
242 CrxUpdateItem::Status to
);
244 CrxUpdateItem
* FindUpdateItemById(const std::string
& id
);
246 void NotifyObservers(Observer::Events event
, const std::string
& id
);
248 bool HasOnDemandItems() const;
250 void OnNewResourceThrottle(base::WeakPtr
<CUResourceThrottle
> rt
,
251 const std::string
& crx_id
);
253 scoped_ptr
<ComponentUpdateService::Configurator
> config_
;
255 scoped_ptr
<UpdateChecker
> update_checker_
;
257 scoped_ptr
<PingManager
> ping_manager_
;
259 scoped_refptr
<ComponentUnpacker
> unpacker_
;
261 scoped_ptr
<CrxDownloader
> crx_downloader_
;
263 // A collection of every work item.
264 typedef std::vector
<CrxUpdateItem
*> UpdateItems
;
265 UpdateItems work_items_
;
267 base::OneShotTimer
<CrxUpdateService
> timer_
;
269 scoped_refptr
<base::SequencedTaskRunner
> blocking_task_runner_
;
271 const Version chrome_version_
;
275 ObserverList
<Observer
> observer_list_
;
277 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService
);
280 //////////////////////////////////////////////////////////////////////////////
282 CrxUpdateService::CrxUpdateService(ComponentUpdateService::Configurator
* config
)
284 ping_manager_(new PingManager(config
->PingUrl(),
285 config
->RequestContext())),
286 blocking_task_runner_(BrowserThread::GetBlockingPool()->
287 GetSequencedTaskRunnerWithShutdownBehavior(
288 BrowserThread::GetBlockingPool()->GetSequenceToken(),
289 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
)),
290 chrome_version_(chrome::VersionInfo().Version()),
294 CrxUpdateService::~CrxUpdateService() {
295 // Because we are a singleton, at this point only the UI thread should be
296 // alive, this simplifies the management of the work that could be in
297 // flight in other threads.
299 STLDeleteElements(&work_items_
);
302 void CrxUpdateService::AddObserver(Observer
* observer
) {
303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
304 observer_list_
.AddObserver(observer
);
307 void CrxUpdateService::RemoveObserver(Observer
* observer
) {
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
309 observer_list_
.RemoveObserver(observer
);
312 ComponentUpdateService::Status
CrxUpdateService::Start() {
313 // Note that RegisterComponent will call Start() when the first
314 // component is registered, so it can be called twice. This way
315 // we avoid scheduling the timer if there is no work to do.
316 VLOG(1) << "CrxUpdateService starting up";
318 if (work_items_
.empty())
321 NotifyObservers(Observer::COMPONENT_UPDATER_STARTED
, "");
323 VLOG(1) << "First update attempt will take place in "
324 << config_
->InitialDelay() << " seconds";
325 timer_
.Start(FROM_HERE
, base::TimeDelta::FromSeconds(config_
->InitialDelay()),
326 this, &CrxUpdateService::ProcessPendingItems
);
330 // Stop the main check + update loop. In flight operations will be
332 ComponentUpdateService::Status
CrxUpdateService::Stop() {
333 VLOG(1) << "CrxUpdateService stopping";
339 bool CrxUpdateService::HasOnDemandItems() const {
342 static bool IsOnDemand(CrxUpdateItem
* item
) {
343 return item
->on_demand
;
346 return std::find_if(work_items_
.begin(),
348 Helper::IsOnDemand
) != work_items_
.end();
351 // This function sets the timer which will call ProcessPendingItems() or
352 // ProcessRequestedItem() if there is an on_demand item. There
353 // are three kinds of waits:
354 // - a short delay, when there is immediate work to be done.
355 // - a medium delay, when there are updates to be applied within the current
356 // update cycle, or there are components that are still unchecked.
357 // - a long delay when a full check/update cycle has completed for all
359 void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay
) {
360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
361 DCHECK(!update_checker_
);
362 CHECK(!timer_
.IsRunning());
363 // It could be the case that Stop() had been called while a url request
364 // or unpacking was in flight, if so we arrive here but |running_| is
365 // false. In that case do not loop again.
369 // Keep the delay short if in the middle of an update (step_delay),
370 // or there are new requested_work_items_ that have not been processed yet.
371 int64 delay_seconds
= 0;
372 if (!HasOnDemandItems()) {
373 switch (step_delay
) {
374 case kStepDelayShort
:
375 delay_seconds
= config_
->StepDelay();
377 case kStepDelayMedium
:
378 delay_seconds
= config_
->StepDelayMedium();
381 delay_seconds
= config_
->NextCheckDelay();
385 delay_seconds
= config_
->StepDelay();
388 if (step_delay
!= kStepDelayShort
) {
389 NotifyObservers(Observer::COMPONENT_UPDATER_SLEEPING
, "");
391 // Zero is only used for unit tests.
392 if (0 == delay_seconds
)
396 VLOG(1) << "Scheduling next run to occur in " << delay_seconds
<< " seconds";
397 timer_
.Start(FROM_HERE
, base::TimeDelta::FromSeconds(delay_seconds
),
398 this, &CrxUpdateService::ProcessPendingItems
);
401 // Given a extension-like component id, find the associated component.
402 CrxUpdateItem
* CrxUpdateService::FindUpdateItemById(const std::string
& id
) {
403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
404 CrxUpdateItem::FindById
finder(id
);
405 UpdateItems::iterator it
= std::find_if(work_items_
.begin(),
408 return it
!= work_items_
.end() ? *it
: NULL
;
411 // Changes a component's status, clearing on_demand and firing notifications as
412 // necessary. By convention, this is the only function that can change a
413 // CrxUpdateItem's |status|.
414 // TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
415 void CrxUpdateService::ChangeItemState(CrxUpdateItem
* item
,
416 CrxUpdateItem::Status to
) {
417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
418 if (to
== CrxUpdateItem::kNoUpdate
||
419 to
== CrxUpdateItem::kUpdated
||
420 to
== CrxUpdateItem::kUpToDate
) {
421 item
->on_demand
= false;
427 case CrxUpdateItem::kCanUpdate
:
428 NotifyObservers(Observer::COMPONENT_UPDATE_FOUND
, item
->id
);
430 case CrxUpdateItem::kUpdatingDiff
:
431 case CrxUpdateItem::kUpdating
:
432 NotifyObservers(Observer::COMPONENT_UPDATE_READY
, item
->id
);
434 case CrxUpdateItem::kUpdated
:
435 NotifyObservers(Observer::COMPONENT_UPDATED
, item
->id
);
437 case CrxUpdateItem::kUpToDate
:
438 case CrxUpdateItem::kNoUpdate
:
439 NotifyObservers(Observer::COMPONENT_NOT_UPDATED
, item
->id
);
441 case CrxUpdateItem::kNew
:
442 case CrxUpdateItem::kChecking
:
443 case CrxUpdateItem::kDownloading
:
444 case CrxUpdateItem::kDownloadingDiff
:
445 case CrxUpdateItem::kLastStatus
:
446 // No notification for these states.
450 // Free possible pending network requests.
451 if ((to
== CrxUpdateItem::kUpdated
) ||
452 (to
== CrxUpdateItem::kUpToDate
) ||
453 (to
== CrxUpdateItem::kNoUpdate
)) {
454 UnblockandReapAllThrottles(&item
->throttles
);
458 // Changes all the components in |work_items_| that have |from| status to
459 // |to| status and returns how many have been changed.
460 size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from
,
461 CrxUpdateItem::Status to
) {
462 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
464 for (UpdateItems::iterator it
= work_items_
.begin();
465 it
!= work_items_
.end(); ++it
) {
466 CrxUpdateItem
* item
= *it
;
467 if (item
->status
== from
) {
468 ChangeItemState(item
, to
);
475 // Adds a component to be checked for upgrades. If the component exists it
476 // it will be replaced and the return code is kReplaced.
477 ComponentUpdateService::Status
CrxUpdateService::RegisterComponent(
478 const CrxComponent
& component
) {
479 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
480 if (component
.pk_hash
.empty() ||
481 !component
.version
.IsValid() ||
482 !component
.installer
)
485 std::string
id(GetCrxComponentID(component
));
486 CrxUpdateItem
* uit
= FindUpdateItemById(id
);
488 uit
->component
= component
;
492 uit
= new CrxUpdateItem
;
494 uit
->component
= component
;
496 work_items_
.push_back(uit
);
497 // If this is the first component registered we call Start to
498 // schedule the first timer.
499 if (running_
&& (work_items_
.size() == 1))
505 // Start the process of checking for an update, for a particular component
506 // that was previously registered.
507 // |component_id| is a value returned from GetCrxComponentID().
508 ComponentUpdateService::Status
CrxUpdateService::OnDemandUpdate(
509 const std::string
& component_id
) {
510 return OnDemandUpdateInternal(FindUpdateItemById(component_id
));
513 ComponentUpdateService::Status
CrxUpdateService::OnDemandUpdateInternal(
514 CrxUpdateItem
* uit
) {
518 // Check if the request is too soon.
519 base::TimeDelta delta
= base::Time::Now() - uit
->last_check
;
520 if (delta
< base::TimeDelta::FromSeconds(config_
->OnDemandDelay()))
523 switch (uit
->status
) {
524 // If the item is already in the process of being updated, there is
525 // no point in this call, so return kInProgress.
526 case CrxUpdateItem::kChecking
:
527 case CrxUpdateItem::kCanUpdate
:
528 case CrxUpdateItem::kDownloadingDiff
:
529 case CrxUpdateItem::kDownloading
:
530 case CrxUpdateItem::kUpdatingDiff
:
531 case CrxUpdateItem::kUpdating
:
533 // Otherwise the item was already checked a while back (or it is new),
534 // set its status to kNew to give it a slightly higher priority.
535 case CrxUpdateItem::kNew
:
536 case CrxUpdateItem::kUpdated
:
537 case CrxUpdateItem::kUpToDate
:
538 case CrxUpdateItem::kNoUpdate
:
539 ChangeItemState(uit
, CrxUpdateItem::kNew
);
540 uit
->on_demand
= true;
542 case CrxUpdateItem::kLastStatus
:
543 NOTREACHED() << uit
->status
;
546 // In case the current delay is long, set the timer to a shorter value
547 // to get the ball rolling.
548 if (timer_
.IsRunning()) {
550 timer_
.Start(FROM_HERE
, base::TimeDelta::FromSeconds(config_
->StepDelay()),
551 this, &CrxUpdateService::ProcessPendingItems
);
557 void CrxUpdateService::GetComponents(
558 std::vector
<CrxComponentInfo
>* components
) {
559 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
560 for (UpdateItems::const_iterator it
= work_items_
.begin();
561 it
!= work_items_
.end(); ++it
) {
562 const CrxUpdateItem
* item
= *it
;
563 CrxComponentInfo info
;
564 info
.id
= GetCrxComponentID(item
->component
);
565 info
.version
= item
->component
.version
.GetString();
566 info
.name
= item
->component
.name
;
567 components
->push_back(info
);
571 // This is the main loop of the component updater. It updates one component
572 // at a time if updates are available. Otherwise, it does an update check or
573 // takes a long sleep until the loop runs again.
574 void CrxUpdateService::ProcessPendingItems() {
575 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
577 CrxUpdateItem
* ready_upgrade
= FindReadyComponent();
579 UpdateComponent(ready_upgrade
);
583 if (!CheckForUpdates())
584 ScheduleNextRun(kStepDelayLong
);
587 CrxUpdateItem
* CrxUpdateService::FindReadyComponent() const {
590 static bool IsReadyOnDemand(CrxUpdateItem
* item
) {
591 return item
->on_demand
&& IsReady(item
);
593 static bool IsReady(CrxUpdateItem
* item
) {
594 return item
->status
== CrxUpdateItem::kCanUpdate
;
598 std::vector
<CrxUpdateItem
*>::const_iterator it
= std::find_if(
599 work_items_
.begin(), work_items_
.end(), Helper::IsReadyOnDemand
);
600 if (it
!= work_items_
.end())
602 it
= std::find_if(work_items_
.begin(), work_items_
.end(), Helper::IsReady
);
603 if (it
!= work_items_
.end())
608 // Prepares the components for an update check and initiates the request.
609 // On demand components are always included in the update check request.
610 // Otherwise, only include components that have not been checked recently.
611 bool CrxUpdateService::CheckForUpdates() {
612 const base::TimeDelta minimum_recheck_wait_time
=
613 base::TimeDelta::FromSeconds(config_
->MinimumReCheckWait());
614 const base::Time
now(base::Time::Now());
616 std::vector
<CrxUpdateItem
*> items_to_check
;
617 for (size_t i
= 0; i
!= work_items_
.size(); ++i
) {
618 CrxUpdateItem
* item
= work_items_
[i
];
619 DCHECK(item
->status
== CrxUpdateItem::kNew
||
620 item
->status
== CrxUpdateItem::kNoUpdate
||
621 item
->status
== CrxUpdateItem::kUpToDate
||
622 item
->status
== CrxUpdateItem::kUpdated
);
624 const base::TimeDelta
time_since_last_checked(now
- item
->last_check
);
626 if (!item
->on_demand
&&
627 time_since_last_checked
< minimum_recheck_wait_time
) {
628 VLOG(1) << "Skipping check for component update: id=" << item
->id
629 << ", time_since_last_checked="
630 << time_since_last_checked
.InSeconds()
631 << " seconds: too soon to check for an update";
635 VLOG(1) << "Scheduling update check for component id=" << item
->id
636 << ", time_since_last_checked="
637 << time_since_last_checked
.InSeconds()
640 ChangeItemState(item
, CrxUpdateItem::kChecking
);
642 item
->last_check
= now
;
643 item
->crx_urls
.clear();
644 item
->crx_diffurls
.clear();
645 item
->previous_version
= item
->component
.version
;
646 item
->next_version
= Version();
647 item
->previous_fp
= item
->component
.fingerprint
;
648 item
->next_fp
.clear();
649 item
->diff_update_failed
= false;
650 item
->error_category
= 0;
651 item
->error_code
= 0;
652 item
->extra_code1
= 0;
653 item
->diff_error_category
= 0;
654 item
->diff_error_code
= 0;
655 item
->diff_extra_code1
= 0;
656 item
->download_metrics
.clear();
658 items_to_check
.push_back(item
);
661 if (items_to_check
.empty())
664 update_checker_
= UpdateChecker::Create(
665 config_
->UpdateUrl(),
666 config_
->RequestContext(),
667 base::Bind(&CrxUpdateService::UpdateCheckComplete
,
668 base::Unretained(this))).Pass();
669 return update_checker_
->CheckForUpdates(items_to_check
,
670 config_
->ExtraRequestParams());
673 void CrxUpdateService::UpdateComponent(CrxUpdateItem
* workitem
) {
674 scoped_ptr
<CRXContext
> crx_context(new CRXContext
);
675 crx_context
->pk_hash
= workitem
->component
.pk_hash
;
676 crx_context
->id
= workitem
->id
;
677 crx_context
->installer
= workitem
->component
.installer
;
678 crx_context
->fingerprint
= workitem
->next_fp
;
679 const std::vector
<GURL
>* urls
= NULL
;
680 bool allow_background_download
= false;
681 if (CanTryDiffUpdate(workitem
, *config_
)) {
682 urls
= &workitem
->crx_diffurls
;
683 ChangeItemState(workitem
, CrxUpdateItem::kDownloadingDiff
);
685 // Background downloads are enabled only for selected components and
686 // only for full downloads (see issue 340448).
687 allow_background_download
= workitem
->component
.allow_background_download
;
688 urls
= &workitem
->crx_urls
;
689 ChangeItemState(workitem
, CrxUpdateItem::kDownloading
);
692 // On demand component updates are always downloaded in foreground.
693 const bool is_background_download
=
694 !workitem
->on_demand
&& allow_background_download
&&
695 config_
->UseBackgroundDownloader();
697 crx_downloader_
.reset(CrxDownloader::Create(is_background_download
,
698 config_
->RequestContext(),
699 blocking_task_runner_
));
700 crx_downloader_
->StartDownload(*urls
,
701 base::Bind(&CrxUpdateService::DownloadComplete
,
702 base::Unretained(this),
703 base::Passed(&crx_context
)));
706 void CrxUpdateService::UpdateCheckComplete(
708 const std::string
& error_message
,
709 const UpdateResponse::Results
& results
) {
710 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
711 update_checker_
.reset();
713 OnUpdateCheckSucceeded(results
);
715 OnUpdateCheckFailed(error
, error_message
);
718 // Handles a valid Omaha update check response by matching the results with
719 // the registered components which were checked for updates.
720 // If updates are found, prepare the components for the actual version upgrade.
721 // One of these components will be drafted for the upgrade next time
722 // ProcessPendingItems is called.
723 void CrxUpdateService::OnUpdateCheckSucceeded(
724 const UpdateResponse::Results
& results
) {
725 size_t num_updates_pending
= 0;
726 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
727 VLOG(1) << "Update check succeeded.";
728 std::vector
<UpdateResponse::Result
>::const_iterator it
;
729 for (it
= results
.list
.begin(); it
!= results
.list
.end(); ++it
) {
730 CrxUpdateItem
* crx
= FindUpdateItemById(it
->extension_id
);
734 if (crx
->status
!= CrxUpdateItem::kChecking
) {
736 continue; // Not updating this component now.
739 if (it
->manifest
.version
.empty()) {
740 // No version means no update available.
741 ChangeItemState(crx
, CrxUpdateItem::kNoUpdate
);
742 VLOG(1) << "No update available for component: " << crx
->id
;
746 if (!IsVersionNewer(crx
->component
.version
, it
->manifest
.version
)) {
747 // The component is up to date.
748 ChangeItemState(crx
, CrxUpdateItem::kUpToDate
);
749 VLOG(1) << "Component already up-to-date: " << crx
->id
;
753 if (!it
->manifest
.browser_min_version
.empty()) {
754 if (IsVersionNewer(chrome_version_
, it
->manifest
.browser_min_version
)) {
755 // The component is not compatible with this Chrome version.
756 VLOG(1) << "Ignoring incompatible component: " << crx
->id
;
757 ChangeItemState(crx
, CrxUpdateItem::kNoUpdate
);
762 if (it
->manifest
.packages
.size() != 1) {
763 // Assume one and only one package per component.
764 VLOG(1) << "Ignoring multiple packages for component: " << crx
->id
;
765 ChangeItemState(crx
, CrxUpdateItem::kNoUpdate
);
769 // Parse the members of the result and queue an upgrade for this component.
770 crx
->next_version
= Version(it
->manifest
.version
);
772 VLOG(1) << "Update found for component: " << crx
->id
;
774 typedef UpdateResponse::Result::Manifest::Package Package
;
775 const Package
& package(it
->manifest
.packages
[0]);
776 crx
->next_fp
= package
.fingerprint
;
778 // Resolve the urls by combining the base urls with the package names.
779 for (size_t i
= 0; i
!= it
->crx_urls
.size(); ++i
) {
780 const GURL
url(it
->crx_urls
[i
].Resolve(package
.name
));
782 crx
->crx_urls
.push_back(url
);
784 for (size_t i
= 0; i
!= it
->crx_diffurls
.size(); ++i
) {
785 const GURL
url(it
->crx_diffurls
[i
].Resolve(package
.namediff
));
787 crx
->crx_diffurls
.push_back(url
);
790 ChangeItemState(crx
, CrxUpdateItem::kCanUpdate
);
791 ++num_updates_pending
;
794 // All components that are not included in the update response are
795 // considered up to date.
796 ChangeItemStatus(CrxUpdateItem::kChecking
, CrxUpdateItem::kUpToDate
);
798 // If there are updates pending we do a short wait, otherwise we take
799 // a longer delay until we check the components again.
800 ScheduleNextRun(num_updates_pending
> 0 ? kStepDelayShort
: kStepDelayLong
);
803 // TODO: record UMA stats.
804 void CrxUpdateService::OnUpdateCheckFailed(int error
,
805 const std::string
& error_message
) {
806 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
808 size_t count
= ChangeItemStatus(CrxUpdateItem::kChecking
,
809 CrxUpdateItem::kNoUpdate
);
810 DCHECK_GT(count
, 0ul);
811 VLOG(1) << "Update check failed.";
812 ScheduleNextRun(kStepDelayLong
);
815 // Called when the CRX package has been downloaded to a temporary location.
816 // Here we fire the notifications and schedule the component-specific installer
817 // to be called in the file thread.
818 void CrxUpdateService::DownloadComplete(
819 scoped_ptr
<CRXContext
> crx_context
,
820 const CrxDownloader::Result
& download_result
) {
821 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
823 CrxUpdateItem
* crx
= FindUpdateItemById(crx_context
->id
);
824 DCHECK(crx
->status
== CrxUpdateItem::kDownloadingDiff
||
825 crx
->status
== CrxUpdateItem::kDownloading
);
827 AppendDownloadMetrics(crx_downloader_
->download_metrics(),
828 &crx
->download_metrics
);
830 if (download_result
.error
) {
831 if (crx
->status
== CrxUpdateItem::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::kDownloadingDiff
,
836 CrxUpdateItem::kCanUpdate
);
837 DCHECK_EQ(count
, 1ul);
838 crx_downloader_
.reset();
840 ScheduleNextRun(kStepDelayShort
);
843 crx
->error_category
= kNetworkError
;
844 crx
->error_code
= download_result
.error
;
845 size_t count
= ChangeItemStatus(CrxUpdateItem::kDownloading
,
846 CrxUpdateItem::kNoUpdate
);
847 DCHECK_EQ(count
, 1ul);
848 crx_downloader_
.reset();
850 // At this point, since both the differential and the full downloads failed,
851 // the update for this component has finished with an error.
852 ping_manager_
->OnUpdateComplete(crx
);
854 // Move on to the next update, if there is one available.
855 ScheduleNextRun(kStepDelayMedium
);
858 if (crx
->status
== CrxUpdateItem::kDownloadingDiff
) {
859 count
= ChangeItemStatus(CrxUpdateItem::kDownloadingDiff
,
860 CrxUpdateItem::kUpdatingDiff
);
862 count
= ChangeItemStatus(CrxUpdateItem::kDownloading
,
863 CrxUpdateItem::kUpdating
);
865 DCHECK_EQ(count
, 1ul);
866 crx_downloader_
.reset();
868 // Why unretained? See comment at top of file.
869 blocking_task_runner_
->PostDelayedTask(
871 base::Bind(&CrxUpdateService::Install
,
872 base::Unretained(this),
873 base::Passed(&crx_context
),
874 download_result
.response
),
875 base::TimeDelta::FromMilliseconds(config_
->StepDelay()));
879 // Install consists of digital signature verification, unpacking and then
880 // calling the component specific installer. All that is handled by the
881 // |unpacker_|. If there is an error this function is in charge of deleting
882 // the files created.
883 void CrxUpdateService::Install(scoped_ptr
<CRXContext
> context
,
884 const base::FilePath
& crx_path
) {
885 // This function owns the file at |crx_path| and the |context| object.
886 unpacker_
= new ComponentUnpacker(context
->pk_hash
,
888 context
->fingerprint
,
890 config_
->InProcess(),
891 blocking_task_runner_
);
892 unpacker_
->Unpack(base::Bind(&CrxUpdateService::EndUnpacking
,
893 base::Unretained(this),
898 void CrxUpdateService::EndUnpacking(const std::string
& component_id
,
899 const base::FilePath
& crx_path
,
900 ComponentUnpacker::Error error
,
901 int extended_error
) {
902 if (!DeleteFileAndEmptyParentDirectory(crx_path
))
903 NOTREACHED() << crx_path
.value();
904 BrowserThread::PostDelayedTask(
907 base::Bind(&CrxUpdateService::DoneInstalling
, base::Unretained(this),
908 component_id
, error
, extended_error
),
909 base::TimeDelta::FromMilliseconds(config_
->StepDelay()));
910 // Reset the unpacker last, otherwise we free our own arguments.
914 // Installation has been completed. Adjust the component status and
915 // schedule the next check. Schedule a short delay before trying the full
916 // update when the differential update failed.
917 void CrxUpdateService::DoneInstalling(const std::string
& component_id
,
918 ComponentUnpacker::Error error
,
920 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
922 ErrorCategory error_category
= kErrorNone
;
924 case ComponentUnpacker::kNone
:
926 case ComponentUnpacker::kInstallerError
:
927 error_category
= kInstallError
;
930 error_category
= kUnpackError
;
934 const bool is_success
= error
== ComponentUnpacker::kNone
;
936 CrxUpdateItem
* item
= FindUpdateItemById(component_id
);
937 if (item
->status
== CrxUpdateItem::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::kUpdatingDiff
,
943 CrxUpdateItem::kCanUpdate
);
944 DCHECK_EQ(count
, 1ul);
945 ScheduleNextRun(kStepDelayShort
);
950 ChangeItemState(item
, CrxUpdateItem::kUpdated
);
951 item
->component
.version
= item
->next_version
;
952 item
->component
.fingerprint
= item
->next_fp
;
954 ChangeItemState(item
, CrxUpdateItem::kNoUpdate
);
955 item
->error_category
= error_category
;
956 item
->error_code
= error
;
957 item
->extra_code1
= extra_code
;
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(BrowserThread::CurrentlyOn(BrowserThread::UI
));
969 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnEvent(event
, id
));
972 content::ResourceThrottle
* CrxUpdateService::GetOnDemandResourceThrottle(
973 net::URLRequest
* request
, const std::string
& crx_id
) {
974 // We give the raw pointer to the caller, who will delete it at will
975 // and we keep for ourselves a weak pointer to it so we can post tasks
976 // from the UI thread without having to track lifetime directly.
977 CUResourceThrottle
* rt
= new CUResourceThrottle(request
);
978 BrowserThread::PostTask(
981 base::Bind(&CrxUpdateService::OnNewResourceThrottle
,
982 base::Unretained(this),
988 void CrxUpdateService::OnNewResourceThrottle(
989 base::WeakPtr
<CUResourceThrottle
> rt
, const std::string
& crx_id
) {
990 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
991 // Check if we can on-demand update, else unblock the request anyway.
992 CrxUpdateItem
* item
= FindUpdateItemById(crx_id
);
993 Status status
= OnDemandUpdateInternal(item
);
994 if (status
== kOk
|| status
== kInProgress
) {
995 item
->throttles
.push_back(rt
);
998 UnblockResourceThrottle(rt
);
1001 ///////////////////////////////////////////////////////////////////////////////
1003 CUResourceThrottle::CUResourceThrottle(const net::URLRequest
* request
)
1005 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1008 CUResourceThrottle::~CUResourceThrottle() {
1009 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1012 void CUResourceThrottle::WillStartRequest(bool* defer
) {
1013 if (state_
!= UNBLOCKED
) {
1021 void CUResourceThrottle::WillRedirectRequest(const GURL
& new_url
, bool* defer
) {
1022 WillStartRequest(defer
);
1025 const char* CUResourceThrottle::GetNameForLogging() const {
1026 return "ComponentUpdateResourceThrottle";
1029 void CUResourceThrottle::Unblock() {
1030 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1031 if (state_
== BLOCKED
)
1032 controller()->Resume();
1036 // The component update factory. Using the component updater as a singleton
1037 // is the job of the browser process.
1038 ComponentUpdateService
* ComponentUpdateServiceFactory(
1039 ComponentUpdateService::Configurator
* config
) {
1041 return new CrxUpdateService(config
);
1044 } // namespace component_updater