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.
4
5 #include "components/component_updater/component_updater_service.h"
6
7 #include <algorithm>
8 #include <set>
9 #include <vector>
10
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"
37 #include "url/gurl.h"
38
39 namespace component_updater {
40
41 // The component updater is designed to live until process shutdown, so
42 // base::Bind() calls are not refcounted.
43
44 namespace {
45
46 // Returns true if the |proposed| version is newer than |current| version.
IsVersionNewer(const Version & current,const std::string & proposed)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;
50 }
51
52 // Returns true if a differential update is available, it has not failed yet,
53 // and the configuration allows it.
CanTryDiffUpdate(const CrxUpdateItem * update_item,const Configurator & config)54 bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
55 const Configurator& config) {
56 return HasDiffUpdate(update_item) && !update_item->diff_update_failed &&
57 config.DeltasEnabled();
58 }
59
AppendDownloadMetrics(const std::vector<CrxDownloader::DownloadMetrics> & source,std::vector<CrxDownloader::DownloadMetrics> * destination)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());
64 }
65
66 } // namespace
67
CrxUpdateItem()68 CrxUpdateItem::CrxUpdateItem()
69 : status(kNew),
70 on_demand(false),
71 diff_update_failed(false),
72 error_category(0),
73 error_code(0),
74 extra_code1(0),
75 diff_error_category(0),
76 diff_error_code(0),
77 diff_extra_code1(0) {
78 }
79
~CrxUpdateItem()80 CrxUpdateItem::~CrxUpdateItem() {
81 }
82
CrxComponent()83 CrxComponent::CrxComponent()
84 : installer(NULL), allow_background_download(true) {
85 }
86
~CrxComponent()87 CrxComponent::~CrxComponent() {
88 }
89
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
102 // thread.
103 class CrxUpdateService : public ComponentUpdateService, public OnDemandUpdater {
104 public:
105 explicit CrxUpdateService(Configurator* config);
106 virtual ~CrxUpdateService();
107
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()
119 OVERRIDE;
120
121 // Context for a crx download url request.
122 struct CRXContext {
123 ComponentInstaller* installer;
124 std::vector<uint8_t> pk_hash;
125 std::string id;
126 std::string fingerprint;
CRXContextcomponent_updater::CrxUpdateService::CRXContext127 CRXContext() : installer(NULL) {}
128 };
129
130 private:
131 enum ErrorCategory {
132 kErrorNone = 0,
133 kNetworkError,
134 kUnpackError,
135 kInstallError,
136 };
137
138 enum StepDelayInterval {
139 kStepDelayShort = 0,
140 kStepDelayMedium,
141 kStepDelayLong,
142 };
143
144 // Overrides for ComponentUpdateService.
145 virtual bool GetComponentDetails(const std::string& component_id,
146 CrxUpdateItem* item) const OVERRIDE;
147
148 // Overrides for OnDemandUpdater.
149 virtual Status OnDemandUpdate(const std::string& component_id) OVERRIDE;
150
151 void UpdateCheckComplete(const GURL& original_url,
152 int error,
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);
157
158 void DownloadProgress(const std::string& component_id,
159 const CrxDownloader::Result& download_result);
160
161 void DownloadComplete(scoped_ptr<CRXContext> crx_context,
162 const CrxDownloader::Result& download_result);
163
164 Status OnDemandUpdateInternal(CrxUpdateItem* item);
165 Status OnDemandUpdateWithCooldown(CrxUpdateItem* item);
166
167 void ProcessPendingItems();
168
169 // Find a component that is ready to update.
170 CrxUpdateItem* FindReadyComponent() const;
171
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();
176
177 void UpdateComponent(CrxUpdateItem* workitem);
178
179 void ScheduleNextRun(StepDelayInterval step_delay);
180
181 void ParseResponse(const std::string& xml);
182
183 void Install(scoped_ptr<CRXContext> context, const base::FilePath& crx_path);
184
185 void EndUnpacking(const std::string& component_id,
186 const base::FilePath& crx_path,
187 ComponentUnpacker::Error error,
188 int extended_error);
189
190 void DoneInstalling(const std::string& component_id,
191 ComponentUnpacker::Error error,
192 int extended_error);
193
194 void ChangeItemState(CrxUpdateItem* item, CrxUpdateItem::Status to);
195
196 size_t ChangeItemStatus(CrxUpdateItem::Status from, CrxUpdateItem::Status to);
197
198 CrxUpdateItem* FindUpdateItemById(const std::string& id) const;
199
200 void NotifyObservers(Observer::Events event, const std::string& id);
201
202 bool HasOnDemandItems() const;
203
204 Status GetServiceStatus(const CrxUpdateItem::Status status);
205
206 scoped_ptr<Configurator> config_;
207
208 scoped_ptr<UpdateChecker> update_checker_;
209
210 scoped_ptr<PingManager> ping_manager_;
211
212 scoped_refptr<ComponentUnpacker> unpacker_;
213
214 scoped_ptr<CrxDownloader> crx_downloader_;
215
216 // A collection of every work item.
217 typedef std::vector<CrxUpdateItem*> UpdateItems;
218 UpdateItems work_items_;
219
220 base::OneShotTimer<CrxUpdateService> timer_;
221
222 base::ThreadChecker thread_checker_;
223
224 // Used to post responses back to the main thread.
225 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
226
227 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
228
229 bool running_;
230
231 ObserverList<Observer> observer_list_;
232
233 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
234 };
235
236 //////////////////////////////////////////////////////////////////////////////
237
CrxUpdateService(Configurator * config)238 CrxUpdateService::CrxUpdateService(Configurator* config)
239 : config_(config),
240 ping_manager_(new PingManager(*config)),
241 main_task_runner_(base::MessageLoopProxy::current()),
242 blocking_task_runner_(config->GetSequencedTaskRunner()),
243 running_(false) {
244 }
245
~CrxUpdateService()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.
250 Stop();
251 STLDeleteElements(&work_items_);
252 }
253
AddObserver(Observer * observer)254 void CrxUpdateService::AddObserver(Observer* observer) {
255 DCHECK(thread_checker_.CalledOnValidThread());
256 observer_list_.AddObserver(observer);
257 }
258
RemoveObserver(Observer * observer)259 void CrxUpdateService::RemoveObserver(Observer* observer) {
260 DCHECK(thread_checker_.CalledOnValidThread());
261 observer_list_.RemoveObserver(observer);
262 }
263
Start()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";
269 running_ = true;
270 if (work_items_.empty())
271 return kOk;
272
273 NotifyObservers(Observer::COMPONENT_UPDATER_STARTED, "");
274
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()),
279 this,
280 &CrxUpdateService::ProcessPendingItems);
281 return kOk;
282 }
283
284 // Stop the main check + update loop. In flight operations will be
285 // completed.
Stop()286 ComponentUpdateService::Status CrxUpdateService::Stop() {
287 VLOG(1) << "CrxUpdateService stopping";
288 running_ = false;
289 timer_.Stop();
290 return kOk;
291 }
292
HasOnDemandItems() const293 bool CrxUpdateService::HasOnDemandItems() const {
294 class Helper {
295 public:
296 static bool IsOnDemand(CrxUpdateItem* item) { return item->on_demand; }
297 };
298 return std::find_if(work_items_.begin(),
299 work_items_.end(),
300 Helper::IsOnDemand) != work_items_.end();
301 }
302
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
310 // components.
ScheduleNextRun(StepDelayInterval step_delay)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.
318 if (!running_)
319 return;
320
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();
328 break;
329 case kStepDelayMedium:
330 delay_seconds = config_->StepDelayMedium();
331 break;
332 case kStepDelayLong:
333 delay_seconds = config_->NextCheckDelay();
334 break;
335 }
336 } else {
337 delay_seconds = config_->StepDelay();
338 }
339
340 if (step_delay != kStepDelayShort) {
341 NotifyObservers(Observer::COMPONENT_UPDATER_SLEEPING, "");
342
343 // Zero is only used for unit tests.
344 if (0 == delay_seconds)
345 return;
346 }
347
348 VLOG(1) << "Scheduling next run to occur in " << delay_seconds << " seconds";
349 timer_.Start(FROM_HERE,
350 base::TimeDelta::FromSeconds(delay_seconds),
351 this,
352 &CrxUpdateService::ProcessPendingItems);
353 }
354
355 // Given a extension-like component id, find the associated component.
FindUpdateItemById(const std::string & id) const356 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;
363 }
364
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?
ChangeItemState(CrxUpdateItem * item,CrxUpdateItem::Status to)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;
375 }
376
377 item->status = to;
378
379 switch (to) {
380 case CrxUpdateItem::kCanUpdate:
381 NotifyObservers(Observer::COMPONENT_UPDATE_FOUND, item->id);
382 break;
383 case CrxUpdateItem::kUpdatingDiff:
384 case CrxUpdateItem::kUpdating:
385 NotifyObservers(Observer::COMPONENT_UPDATE_READY, item->id);
386 break;
387 case CrxUpdateItem::kUpdated:
388 NotifyObservers(Observer::COMPONENT_UPDATED, item->id);
389 break;
390 case CrxUpdateItem::kUpToDate:
391 case CrxUpdateItem::kNoUpdate:
392 NotifyObservers(Observer::COMPONENT_NOT_UPDATED, item->id);
393 break;
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.
400 break;
401 }
402
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();
409 ++it) {
410 it->Run();
411 }
412 item->ready_callbacks.clear();
413 }
414 }
415
416 // Changes all the components in |work_items_| that have |from| status to
417 // |to| status and returns how many have been changed.
ChangeItemStatus(CrxUpdateItem::Status from,CrxUpdateItem::Status to)418 size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::Status from,
419 CrxUpdateItem::Status to) {
420 DCHECK(thread_checker_.CalledOnValidThread());
421 size_t count = 0;
422 for (UpdateItems::iterator it = work_items_.begin();
423 it != work_items_.end();
424 ++it) {
425 CrxUpdateItem* item = *it;
426 if (item->status == from) {
427 ChangeItemState(item, to);
428 ++count;
429 }
430 }
431 return count;
432 }
433
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.
RegisterComponent(const CrxComponent & component)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)
441 return kError;
442
443 std::string id(GetCrxComponentID(component));
444 CrxUpdateItem* uit = FindUpdateItemById(id);
445 if (uit) {
446 uit->component = component;
447 return kReplaced;
448 }
449
450 uit = new CrxUpdateItem;
451 uit->id.swap(id);
452 uit->component = component;
453
454 work_items_.push_back(uit);
455
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.
462 if (running_) {
463 if (work_items_.size() == 1) {
464 Start();
465 } else if (timer_.IsRunning()) {
466 timer_.Start(FROM_HERE,
467 base::TimeDelta::FromSeconds(config_->InitialDelay()),
468 this,
469 &CrxUpdateService::ProcessPendingItems);
470 }
471 }
472
473 return kOk;
474 }
475
GetComponentIDs() const476 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();
481 ++it) {
482 const CrxUpdateItem* item = *it;
483 component_ids.push_back(item->id);
484 }
485 return component_ids;
486 }
487
GetOnDemandUpdater()488 OnDemandUpdater& CrxUpdateService::GetOnDemandUpdater() {
489 return *this;
490 }
491
MaybeThrottle(const std::string & crx_id,const base::Closure & callback)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);
500 return;
501 }
502 callback.Run();
503 }
504
505 scoped_refptr<base::SequencedTaskRunner>
GetSequencedTaskRunner()506 CrxUpdateService::GetSequencedTaskRunner() {
507 return config_->GetSequencedTaskRunner();
508 }
509
GetComponentDetails(const std::string & component_id,CrxUpdateItem * item) const510 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));
514 if (crx_update_item)
515 *item = *crx_update_item;
516 return crx_update_item != NULL;
517 }
518
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().
OnDemandUpdate(const std::string & component_id)522 ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate(
523 const std::string& component_id) {
524 return OnDemandUpdateInternal(FindUpdateItemById(component_id));
525 }
526
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.
ProcessPendingItems()530 void CrxUpdateService::ProcessPendingItems() {
531 DCHECK(thread_checker_.CalledOnValidThread());
532
533 CrxUpdateItem* ready_upgrade = FindReadyComponent();
534 if (ready_upgrade) {
535 UpdateComponent(ready_upgrade);
536 return;
537 }
538
539 if (!CheckForUpdates())
540 ScheduleNextRun(kStepDelayLong);
541 }
542
FindReadyComponent() const543 CrxUpdateItem* CrxUpdateService::FindReadyComponent() const {
544 class Helper {
545 public:
546 static bool IsReadyOnDemand(CrxUpdateItem* item) {
547 return item->on_demand && IsReady(item);
548 }
549 static bool IsReady(CrxUpdateItem* item) {
550 return item->status == CrxUpdateItem::kCanUpdate;
551 }
552 };
553
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())
557 return *it;
558 it = std::find_if(work_items_.begin(), work_items_.end(), Helper::IsReady);
559 if (it != work_items_.end())
560 return *it;
561 return NULL;
562 }
563
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.
CheckForUpdates()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());
571
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);
579
580 const base::TimeDelta time_since_last_checked(now - item->last_check);
581
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";
588 continue;
589 }
590
591 VLOG(1) << "Scheduling update check for component id=" << item->id
592 << ", time_since_last_checked="
593 << time_since_last_checked.InSeconds() << " seconds";
594
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();
610
611 items_to_check.push_back(item);
612
613 ChangeItemState(item, CrxUpdateItem::kChecking);
614 }
615
616 if (items_to_check.empty())
617 return false;
618
619 update_checker_ = UpdateChecker::Create(*config_).Pass();
620 return update_checker_->CheckForUpdates(
621 items_to_check,
622 config_->ExtraRequestParams(),
623 base::Bind(&CrxUpdateService::UpdateCheckComplete,
624 base::Unretained(this)));
625 }
626
UpdateComponent(CrxUpdateItem * workitem)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);
638 } else {
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);
644 }
645
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();
650
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),
659 crx_context->id));
660 crx_downloader_->StartDownload(*urls,
661 base::Bind(&CrxUpdateService::DownloadComplete,
662 base::Unretained(this),
663 base::Passed(&crx_context)));
664 }
665
UpdateCheckComplete(const GURL & original_url,int error,const std::string & error_message,const UpdateResponse::Results & results)666 void CrxUpdateService::UpdateCheckComplete(
667 const GURL& original_url,
668 int error,
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();
674 if (!error)
675 OnUpdateCheckSucceeded(results);
676 else
677 OnUpdateCheckFailed(error, error_message);
678 }
679
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.
OnUpdateCheckSucceeded(const UpdateResponse::Results & results)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);
693 if (!crx)
694 continue;
695
696 if (crx->status != CrxUpdateItem::kChecking) {
697 NOTREACHED();
698 continue; // Not updating this component now.
699 }
700
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;
705 continue;
706 }
707
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;
712 continue;
713 }
714
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);
721 continue;
722 }
723 }
724
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);
729 continue;
730 }
731
732 // Parse the members of the result and queue an upgrade for this component.
733 crx->next_version = Version(it->manifest.version);
734
735 VLOG(1) << "Update found for component: " << crx->id;
736
737 typedef UpdateResponse::Result::Manifest::Package Package;
738 const Package& package(it->manifest.packages[0]);
739 crx->next_fp = package.fingerprint;
740
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));
744 if (url.is_valid())
745 crx->crx_urls.push_back(url);
746 }
747 for (size_t i = 0; i != it->crx_diffurls.size(); ++i) {
748 const GURL url(it->crx_diffurls[i].Resolve(package.namediff));
749 if (url.is_valid())
750 crx->crx_diffurls.push_back(url);
751 }
752
753 ChangeItemState(crx, CrxUpdateItem::kCanUpdate);
754 ++num_updates_pending;
755 }
756
757 // All components that are not included in the update response are
758 // considered up to date.
759 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
760
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);
764 }
765
OnUpdateCheckFailed(int error,const std::string & error_message)766 void CrxUpdateService::OnUpdateCheckFailed(int error,
767 const std::string& error_message) {
768 DCHECK(thread_checker_.CalledOnValidThread());
769 DCHECK(error);
770 size_t count =
771 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kNoUpdate);
772 DCHECK_GT(count, 0ul);
773 VLOG(1) << "Update check failed.";
774 ScheduleNextRun(kStepDelayLong);
775 }
776
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.
DownloadProgress(const std::string & component_id,const CrxDownloader::Result & download_result)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);
785 }
786
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.
DownloadComplete(scoped_ptr<CRXContext> crx_context,const CrxDownloader::Result & download_result)790 void CrxUpdateService::DownloadComplete(
791 scoped_ptr<CRXContext> crx_context,
792 const CrxDownloader::Result& download_result) {
793 DCHECK(thread_checker_.CalledOnValidThread());
794
795 CrxUpdateItem* crx = FindUpdateItemById(crx_context->id);
796 DCHECK(crx->status == CrxUpdateItem::kDownloadingDiff ||
797 crx->status == CrxUpdateItem::kDownloading);
798
799 AppendDownloadMetrics(crx_downloader_->download_metrics(),
800 &crx->download_metrics);
801
802 crx_downloader_.reset();
803
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);
812
813 ScheduleNextRun(kStepDelayShort);
814 return;
815 }
816 crx->error_category = kNetworkError;
817 crx->error_code = download_result.error;
818 size_t count =
819 ChangeItemStatus(CrxUpdateItem::kDownloading, CrxUpdateItem::kNoUpdate);
820 DCHECK_EQ(count, 1ul);
821
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);
825
826 // Move on to the next update, if there is one available.
827 ScheduleNextRun(kStepDelayMedium);
828 } else {
829 size_t count = 0;
830 if (crx->status == CrxUpdateItem::kDownloadingDiff) {
831 count = ChangeItemStatus(CrxUpdateItem::kDownloadingDiff,
832 CrxUpdateItem::kUpdatingDiff);
833 } else {
834 count = ChangeItemStatus(CrxUpdateItem::kDownloading,
835 CrxUpdateItem::kUpdating);
836 }
837 DCHECK_EQ(count, 1ul);
838
839 // Why unretained? See comment at top of file.
840 blocking_task_runner_->PostDelayedTask(
841 FROM_HERE,
842 base::Bind(&CrxUpdateService::Install,
843 base::Unretained(this),
844 base::Passed(&crx_context),
845 download_result.response),
846 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
847 }
848 }
849
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.
Install(scoped_ptr<CRXContext> context,const base::FilePath & crx_path)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,
858 crx_path,
859 context->fingerprint,
860 context->installer,
861 config_->CreateOutOfProcessPatcher(),
862 blocking_task_runner_);
863 unpacker_->Unpack(base::Bind(&CrxUpdateService::EndUnpacking,
864 base::Unretained(this),
865 context->id,
866 crx_path));
867 }
868
EndUnpacking(const std::string & component_id,const base::FilePath & crx_path,ComponentUnpacker::Error error,int extended_error)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(
876 FROM_HERE,
877 base::Bind(&CrxUpdateService::DoneInstalling,
878 base::Unretained(this),
879 component_id,
880 error,
881 extended_error),
882 base::TimeDelta::FromMilliseconds(config_->StepDelay()));
883 // Reset the unpacker last, otherwise we free our own arguments.
884 unpacker_ = NULL;
885 }
886
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.
DoneInstalling(const std::string & component_id,ComponentUnpacker::Error error,int extra_code)890 void CrxUpdateService::DoneInstalling(const std::string& component_id,
891 ComponentUnpacker::Error error,
892 int extra_code) {
893 DCHECK(thread_checker_.CalledOnValidThread());
894
895 ErrorCategory error_category = kErrorNone;
896 switch (error) {
897 case ComponentUnpacker::kNone:
898 break;
899 case ComponentUnpacker::kInstallerError:
900 error_category = kInstallError;
901 break;
902 default:
903 error_category = kUnpackError;
904 break;
905 }
906
907 const bool is_success = error == ComponentUnpacker::kNone;
908
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);
919 return;
920 }
921
922 if (is_success) {
923 item->component.version = item->next_version;
924 item->component.fingerprint = item->next_fp;
925 ChangeItemState(item, CrxUpdateItem::kUpdated);
926 } else {
927 item->error_category = error_category;
928 item->error_code = error;
929 item->extra_code1 = extra_code;
930 ChangeItemState(item, CrxUpdateItem::kNoUpdate);
931 }
932
933 ping_manager_->OnUpdateComplete(item);
934
935 // Move on to the next update, if there is one available.
936 ScheduleNextRun(kStepDelayMedium);
937 }
938
NotifyObservers(Observer::Events event,const std::string & id)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));
943 }
944
OnDemandUpdateWithCooldown(CrxUpdateItem * uit)945 ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateWithCooldown(
946 CrxUpdateItem* uit) {
947 if (!uit)
948 return kError;
949
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()))
953 return kError;
954
955 return OnDemandUpdateInternal(uit);
956 }
957
OnDemandUpdateInternal(CrxUpdateItem * uit)958 ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal(
959 CrxUpdateItem* uit) {
960 if (!uit)
961 return kError;
962
963 uit->on_demand = true;
964
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;
974
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);
978 }
979
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()) {
983 timer_.Stop();
984 timer_.Start(FROM_HERE,
985 base::TimeDelta::FromSeconds(config_->StepDelay()),
986 this,
987 &CrxUpdateService::ProcessPendingItems);
988 }
989
990 return kOk;
991 }
992
GetServiceStatus(CrxUpdateItem::Status status)993 ComponentUpdateService::Status CrxUpdateService::GetServiceStatus(
994 CrxUpdateItem::Status status) {
995 switch (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:
1002 return kInProgress;
1003 case CrxUpdateItem::kNew:
1004 case CrxUpdateItem::kUpdated:
1005 case CrxUpdateItem::kUpToDate:
1006 case CrxUpdateItem::kNoUpdate:
1007 return kOk;
1008 case CrxUpdateItem::kLastStatus:
1009 NOTREACHED() << status;
1010 }
1011 return kError;
1012 }
1013
1014 ///////////////////////////////////////////////////////////////////////////////
1015
1016 // The component update factory. Using the component updater as a singleton
1017 // is the job of the browser process.
ComponentUpdateServiceFactory(Configurator * config)1018 ComponentUpdateService* ComponentUpdateServiceFactory(Configurator* config) {
1019 DCHECK(config);
1020 return new CrxUpdateService(config);
1021 }
1022
1023 } // namespace component_updater
1024