OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/component_updater/component_updater_service.h" | 5 #include "chrome/browser/component_updater/component_updater_service.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> |
8 #include <vector> | 9 #include <vector> |
9 | 10 |
10 #include "base/at_exit.h" | 11 #include "base/at_exit.h" |
11 #include "base/bind.h" | 12 #include "base/bind.h" |
12 #include "base/file_path.h" | 13 #include "base/file_path.h" |
13 #include "base/file_util.h" | 14 #include "base/file_util.h" |
14 #include "base/logging.h" | 15 #include "base/logging.h" |
15 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
16 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
17 #include "base/string_piece.h" | 18 #include "base/string_piece.h" |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 class CrxUpdateService : public ComponentUpdateService { | 247 class CrxUpdateService : public ComponentUpdateService { |
247 public: | 248 public: |
248 explicit CrxUpdateService(ComponentUpdateService::Configurator* config); | 249 explicit CrxUpdateService(ComponentUpdateService::Configurator* config); |
249 | 250 |
250 virtual ~CrxUpdateService(); | 251 virtual ~CrxUpdateService(); |
251 | 252 |
252 // Overrides for ComponentUpdateService. | 253 // Overrides for ComponentUpdateService. |
253 virtual Status Start() OVERRIDE; | 254 virtual Status Start() OVERRIDE; |
254 virtual Status Stop() OVERRIDE; | 255 virtual Status Stop() OVERRIDE; |
255 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE; | 256 virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE; |
| 257 virtual Status CheckForUpdateSoon(const CrxComponent& component) OVERRIDE; |
256 | 258 |
257 // The only purpose of this class is to forward the | 259 // The only purpose of this class is to forward the |
258 // UtilityProcessHostClient callbacks so CrxUpdateService does | 260 // UtilityProcessHostClient callbacks so CrxUpdateService does |
259 // not have to derive from it because that is refcounted. | 261 // not have to derive from it because that is refcounted. |
260 class ManifestParserBridge : public UtilityProcessHostClient { | 262 class ManifestParserBridge : public UtilityProcessHostClient { |
261 public: | 263 public: |
262 explicit ManifestParserBridge(CrxUpdateService* service) | 264 explicit ManifestParserBridge(CrxUpdateService* service) |
263 : service_(service) {} | 265 : service_(service) {} |
264 | 266 |
265 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { | 267 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 size_t ChangeItemStatus(CrxUpdateItem::Status from, | 337 size_t ChangeItemStatus(CrxUpdateItem::Status from, |
336 CrxUpdateItem::Status to); | 338 CrxUpdateItem::Status to); |
337 | 339 |
338 CrxUpdateItem* FindUpdateItemById(const std::string& id); | 340 CrxUpdateItem* FindUpdateItemById(const std::string& id); |
339 | 341 |
340 scoped_ptr<Config> config_; | 342 scoped_ptr<Config> config_; |
341 | 343 |
342 scoped_ptr<net::URLFetcher> url_fetcher_; | 344 scoped_ptr<net::URLFetcher> url_fetcher_; |
343 | 345 |
344 typedef std::vector<CrxUpdateItem*> UpdateItems; | 346 typedef std::vector<CrxUpdateItem*> UpdateItems; |
| 347 // A collection of every work item. |
345 UpdateItems work_items_; | 348 UpdateItems work_items_; |
346 | 349 |
| 350 // A particular set of items from work_items_, which should be checked ASAP. |
| 351 std::set<CrxUpdateItem*> requested_work_items_; |
| 352 |
347 base::OneShotTimer<CrxUpdateService> timer_; | 353 base::OneShotTimer<CrxUpdateService> timer_; |
348 | 354 |
349 Version chrome_version_; | 355 Version chrome_version_; |
350 | 356 |
351 bool running_; | 357 bool running_; |
352 | 358 |
353 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService); | 359 DISALLOW_COPY_AND_ASSIGN(CrxUpdateService); |
354 }; | 360 }; |
355 | 361 |
356 ////////////////////////////////////////////////////////////////////////////// | 362 ////////////////////////////////////////////////////////////////////////////// |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 } | 395 } |
390 | 396 |
391 // Stop the main check + update loop. In flight operations will be | 397 // Stop the main check + update loop. In flight operations will be |
392 // completed. | 398 // completed. |
393 ComponentUpdateService::Status CrxUpdateService::Stop() { | 399 ComponentUpdateService::Status CrxUpdateService::Stop() { |
394 running_ = false; | 400 running_ = false; |
395 timer_.Stop(); | 401 timer_.Stop(); |
396 return kOk; | 402 return kOk; |
397 } | 403 } |
398 | 404 |
399 // This function sets the timer which will call ProcessPendingItems() there | 405 // This function sets the timer which will call ProcessPendingItems() or |
400 // are two kind of waits, the short one (with step_delay = true) and the | 406 // ProcessRequestedItem() if there is an important requested item. There |
401 // long one. | 407 // are two kinds of waits: a short step_delay (when step_status is |
| 408 // kPrevInProgress) and a long one when a full check/update cycle |
| 409 // has completed either successfully or with an error. |
402 void CrxUpdateService::ScheduleNextRun(bool step_delay) { | 410 void CrxUpdateService::ScheduleNextRun(bool step_delay) { |
403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
404 DCHECK(url_fetcher_.get() == NULL); | 412 DCHECK(url_fetcher_.get() == NULL); |
405 CHECK(!timer_.IsRunning()); | 413 CHECK(!timer_.IsRunning()); |
406 // It could be the case that Stop() had been called while a url request | 414 // It could be the case that Stop() had been called while a url request |
407 // or unpacking was in flight, if so we arrive here but |running_| is | 415 // or unpacking was in flight, if so we arrive here but |running_| is |
408 // false. In that case do not loop again. | 416 // false. In that case do not loop again. |
409 if (!running_) | 417 if (!running_) |
410 return; | 418 return; |
411 | 419 |
412 int64 delay = step_delay ? config_->StepDelay() : config_->NextCheckDelay(); | 420 // Keep the delay short if in the middle of an update (step_delay), |
| 421 // or there are new requested_work_items_ that have not been processed yet. |
| 422 int64 delay = (step_delay || requested_work_items_.size() > 0) |
| 423 ? config_->StepDelay() : config_->NextCheckDelay(); |
413 | 424 |
414 if (!step_delay) { | 425 if (!step_delay) { |
415 content::NotificationService::current()->Notify( | 426 content::NotificationService::current()->Notify( |
416 chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, | 427 chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, |
417 content::Source<ComponentUpdateService>(this), | 428 content::Source<ComponentUpdateService>(this), |
418 content::NotificationService::NoDetails()); | 429 content::NotificationService::NoDetails()); |
419 // Zero is only used for unit tests. | 430 // Zero is only used for unit tests. |
420 if (0 == delay) | 431 if (0 == delay) |
421 return; | 432 return; |
422 } | 433 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 std::string* query) { | 507 std::string* query) { |
497 if (!AddQueryString(item->id, | 508 if (!AddQueryString(item->id, |
498 item->component.version.GetString(), | 509 item->component.version.GetString(), |
499 config_->UrlSizeLimit(), query)) | 510 config_->UrlSizeLimit(), query)) |
500 return false; | 511 return false; |
501 item->status = CrxUpdateItem::kChecking; | 512 item->status = CrxUpdateItem::kChecking; |
502 item->last_check = base::Time::Now(); | 513 item->last_check = base::Time::Now(); |
503 return true; | 514 return true; |
504 } | 515 } |
505 | 516 |
| 517 // Start the process of checking for an update, for a particular component |
| 518 // that was previously registered. |
| 519 ComponentUpdateService::Status CrxUpdateService::CheckForUpdateSoon( |
| 520 const CrxComponent& component) { |
| 521 if (component.pk_hash.empty() || |
| 522 !component.version.IsValid() || |
| 523 !component.installer) |
| 524 return kError; |
| 525 |
| 526 std::string id = |
| 527 HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0], |
| 528 component.pk_hash.size()/2))); |
| 529 |
| 530 CrxUpdateItem* uit; |
| 531 uit = FindUpdateItemById(id); |
| 532 if (!uit) |
| 533 return kError; |
| 534 |
| 535 // Check if the request is too soon. |
| 536 base::TimeDelta delta = base::Time::Now() - uit->last_check; |
| 537 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay())) { |
| 538 return kError; |
| 539 } |
| 540 |
| 541 switch (uit->status) { |
| 542 // If the item is already in the process of being updated, there is |
| 543 // no point in this call, so return kInProgress. |
| 544 case CrxUpdateItem::kChecking: |
| 545 case CrxUpdateItem::kCanUpdate: |
| 546 case CrxUpdateItem::kDownloading: |
| 547 case CrxUpdateItem::kUpdating: |
| 548 return kInProgress; |
| 549 // Otherwise the item was already checked a while back (or it is new), |
| 550 // set its status to kNew to give it a slightly higher priority. |
| 551 case CrxUpdateItem::kNew: |
| 552 case CrxUpdateItem::kUpdated: |
| 553 case CrxUpdateItem::kUpToDate: |
| 554 case CrxUpdateItem::kNoUpdate: |
| 555 uit->status = CrxUpdateItem::kNew; |
| 556 requested_work_items_.insert(uit); |
| 557 break; |
| 558 case CrxUpdateItem::kLastStatus: |
| 559 NOTREACHED() << uit->status; |
| 560 } |
| 561 |
| 562 // In case the current delay is long, set the timer to a shorter value |
| 563 // to get the ball rolling. |
| 564 if (timer_.IsRunning()) { |
| 565 timer_.Stop(); |
| 566 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(config_->StepDelay()), |
| 567 this, &CrxUpdateService::ProcessPendingItems); |
| 568 } |
| 569 |
| 570 return kOk; |
| 571 } |
| 572 |
506 // Here is where the work gets scheduled. Given that our |work_items_| list | 573 // Here is where the work gets scheduled. Given that our |work_items_| list |
507 // is expected to be ten or less items, we simply loop several times. | 574 // is expected to be ten or less items, we simply loop several times. |
508 void CrxUpdateService::ProcessPendingItems() { | 575 void CrxUpdateService::ProcessPendingItems() { |
509 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
510 // First check for ready upgrades and do one. The first | 577 // First check for ready upgrades and do one. The first |
511 // step is to fetch the crx package. | 578 // step is to fetch the crx package. |
512 for (UpdateItems::const_iterator it = work_items_.begin(); | 579 for (UpdateItems::const_iterator it = work_items_.begin(); |
513 it != work_items_.end(); ++it) { | 580 it != work_items_.end(); ++it) { |
514 CrxUpdateItem* item = *it; | 581 CrxUpdateItem* item = *it; |
515 if (item->status != CrxUpdateItem::kCanUpdate) | 582 if (item->status != CrxUpdateItem::kCanUpdate) |
(...skipping 19 matching lines...) Expand all Loading... |
535 // checked against the server. We can batch some in a single url request. | 602 // checked against the server. We can batch some in a single url request. |
536 for (UpdateItems::const_iterator it = work_items_.begin(); | 603 for (UpdateItems::const_iterator it = work_items_.begin(); |
537 it != work_items_.end(); ++it) { | 604 it != work_items_.end(); ++it) { |
538 CrxUpdateItem* item = *it; | 605 CrxUpdateItem* item = *it; |
539 if (item->status != CrxUpdateItem::kNew) | 606 if (item->status != CrxUpdateItem::kNew) |
540 continue; | 607 continue; |
541 if (item->component.source != manifest_source) | 608 if (item->component.source != manifest_source) |
542 continue; | 609 continue; |
543 if (!AddItemToUpdateCheck(item, &query)) | 610 if (!AddItemToUpdateCheck(item, &query)) |
544 break; | 611 break; |
| 612 // Requested work items may speed up the update cycle up until |
| 613 // the point that we start an update check. I.e., transition |
| 614 // from kNew -> kChecking. Since the service doesn't guarantee that |
| 615 // the requested items make it any further than kChecking, |
| 616 // forget them now. |
| 617 requested_work_items_.erase(item); |
545 } | 618 } |
546 | 619 |
547 // Next we can go back to components we already checked, here | 620 // Next we can go back to components we already checked, here |
548 // we can also batch them in a single url request, as long as | 621 // we can also batch them in a single url request, as long as |
549 // we have not checked them recently. | 622 // we have not checked them recently. |
550 const base::TimeDelta min_delta_time = | 623 const base::TimeDelta min_delta_time = |
551 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait()); | 624 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait()); |
552 | 625 |
553 for (UpdateItems::const_iterator it = work_items_.begin(); | 626 for (UpdateItems::const_iterator it = work_items_.begin(); |
554 it != work_items_.end(); ++it) { | 627 it != work_items_.end(); ++it) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
595 0, GURL(full_query), net::URLFetcher::GET, | 668 0, GURL(full_query), net::URLFetcher::GET, |
596 MakeContextDelegate(this, new UpdateContext()))); | 669 MakeContextDelegate(this, new UpdateContext()))); |
597 StartFetch(url_fetcher_.get(), config_->RequestContext(), false); | 670 StartFetch(url_fetcher_.get(), config_->RequestContext(), false); |
598 return; | 671 return; |
599 } | 672 } |
600 | 673 |
601 // No components to update. Next check after the long sleep. | 674 // No components to update. Next check after the long sleep. |
602 ScheduleNextRun(false); | 675 ScheduleNextRun(false); |
603 } | 676 } |
604 | 677 |
605 // Caled when we got a response from the update server. It consists of an xml | 678 // Called when we got a response from the update server. It consists of an xml |
606 // document following the omaha update scheme. | 679 // document following the omaha update scheme. |
607 void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source, | 680 void CrxUpdateService::OnURLFetchComplete(const net::URLFetcher* source, |
608 UpdateContext* context) { | 681 UpdateContext* context) { |
609 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 682 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
610 if (FetchSuccess(*source)) { | 683 if (FetchSuccess(*source)) { |
611 std::string xml; | 684 std::string xml; |
612 source->GetResponseAsString(&xml); | 685 source->GetResponseAsString(&xml); |
613 url_fetcher_.reset(); | 686 url_fetcher_.reset(); |
614 ParseManifest(xml); | 687 ParseManifest(xml); |
615 } else { | 688 } else { |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 ScheduleNextRun(false); | 872 ScheduleNextRun(false); |
800 } | 873 } |
801 | 874 |
802 // The component update factory. Using the component updater as a singleton | 875 // The component update factory. Using the component updater as a singleton |
803 // is the job of the browser process. | 876 // is the job of the browser process. |
804 ComponentUpdateService* ComponentUpdateServiceFactory( | 877 ComponentUpdateService* ComponentUpdateServiceFactory( |
805 ComponentUpdateService::Configurator* config) { | 878 ComponentUpdateService::Configurator* config) { |
806 DCHECK(config); | 879 DCHECK(config); |
807 return new CrxUpdateService(config); | 880 return new CrxUpdateService(config); |
808 } | 881 } |
OLD | NEW |