OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/at_exit.h" | 10 #include "base/at_exit.h" |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 running_ = false; | 337 running_ = false; |
338 timer_.Stop(); | 338 timer_.Stop(); |
339 return kOk; | 339 return kOk; |
340 } | 340 } |
341 | 341 |
342 // This function sets the timer which will call ProcessPendingItems() there | 342 // This function sets the timer which will call ProcessPendingItems() there |
343 // are two kind of waits, the short one (with step_delay = true) and the | 343 // are two kind of waits, the short one (with step_delay = true) and the |
344 // long one. | 344 // long one. |
345 void CrxUpdateService::ScheduleNextRun(bool step_delay) { | 345 void CrxUpdateService::ScheduleNextRun(bool step_delay) { |
346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 347 DCHECK(url_fetcher_.get() == NULL); |
347 CHECK(!timer_.IsRunning()); | 348 CHECK(!timer_.IsRunning()); |
348 // It could be the case that Stop() had been called while a url request | 349 // It could be the case that Stop() had been called while a url request |
349 // or unpacking was in flight, if so we arrive here but |running_| is | 350 // or unpacking was in flight, if so we arrive here but |running_| is |
350 // false. In that case do not loop again. | 351 // false. In that case do not loop again. |
351 if (!running_) | 352 if (!running_) |
352 return; | 353 return; |
353 | 354 |
| 355 int64 delay = step_delay ? config_->StepDelay() : config_->NextCheckDelay(); |
| 356 |
354 if (!step_delay) { | 357 if (!step_delay) { |
355 NotificationService::current()->Notify( | 358 NotificationService::current()->Notify( |
356 chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, | 359 chrome::NOTIFICATION_COMPONENT_UPDATER_SLEEPING, |
357 Source<ComponentUpdateService>(this), | 360 Source<ComponentUpdateService>(this), |
358 NotificationService::NoDetails()); | 361 NotificationService::NoDetails()); |
359 // Zero is only used for unit tests. | 362 // Zero is only used for unit tests. |
360 if (0 == config_->NextCheckDelay()) | 363 if (0 == delay) |
361 return; | 364 return; |
362 } | 365 } |
363 | 366 |
364 int64 delay = step_delay ? config_->StepDelay() : config_->NextCheckDelay(); | |
365 timer_.Start(base::TimeDelta::FromSeconds(delay), | 367 timer_.Start(base::TimeDelta::FromSeconds(delay), |
366 this, &CrxUpdateService::ProcessPendingItems); | 368 this, &CrxUpdateService::ProcessPendingItems); |
367 } | 369 } |
368 | 370 |
369 // Given a extension-like component id, find the associated component. | 371 // Given a extension-like component id, find the associated component. |
370 CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) { | 372 CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) { |
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 373 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
372 CrxUpdateItem::FindById finder(id); | 374 CrxUpdateItem::FindById finder(id); |
373 UpdateItems::iterator it = std::find_if(work_items_.begin(), | 375 UpdateItems::iterator it = std::find_if(work_items_.begin(), |
374 work_items_.end(), | 376 work_items_.end(), |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 | 484 |
483 // Next we can go back to components we already checked, here | 485 // Next we can go back to components we already checked, here |
484 // we can also batch them in a single url request, as long as | 486 // we can also batch them in a single url request, as long as |
485 // we have not checked them recently. | 487 // we have not checked them recently. |
486 base::TimeDelta min_delta_time = | 488 base::TimeDelta min_delta_time = |
487 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait()); | 489 base::TimeDelta::FromSeconds(config_->MinimumReCheckWait()); |
488 | 490 |
489 for (UpdateItems::const_iterator it = work_items_.begin(); | 491 for (UpdateItems::const_iterator it = work_items_.begin(); |
490 it != work_items_.end(); ++it) { | 492 it != work_items_.end(); ++it) { |
491 CrxUpdateItem* item = *it; | 493 CrxUpdateItem* item = *it; |
492 if ((item->status != CrxUpdateItem::kNoUpdate) || | 494 if ((item->status != CrxUpdateItem::kNoUpdate) && |
493 (item->status != CrxUpdateItem::kUpToDate)) | 495 (item->status != CrxUpdateItem::kUpToDate)) |
494 continue; | 496 continue; |
495 base::TimeDelta delta = base::Time::Now() - item->last_check; | 497 base::TimeDelta delta = base::Time::Now() - item->last_check; |
496 if (delta < min_delta_time) | 498 if (delta < min_delta_time) |
497 continue; | 499 continue; |
498 if (!AddItemToUpdateCheck(item, &query)) | 500 if (!AddItemToUpdateCheck(item, &query)) |
499 break; | 501 break; |
500 } | 502 } |
501 // Finally, we check components that we already updated. | 503 // Finally, we check components that we already updated. |
502 for (UpdateItems::const_iterator it = work_items_.begin(); | 504 for (UpdateItems::const_iterator it = work_items_.begin(); |
(...skipping 22 matching lines...) Expand all Loading... |
525 } | 527 } |
526 | 528 |
527 // Caled when we got a response from the update server. It consists of an xml | 529 // Caled when we got a response from the update server. It consists of an xml |
528 // document following the omaha update scheme. | 530 // document following the omaha update scheme. |
529 void CrxUpdateService::OnURLFetchComplete(const URLFetcher* source, | 531 void CrxUpdateService::OnURLFetchComplete(const URLFetcher* source, |
530 UpdateContext*) { | 532 UpdateContext*) { |
531 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 533 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
532 if (FetchSuccess(*source)) { | 534 if (FetchSuccess(*source)) { |
533 std::string xml; | 535 std::string xml; |
534 source->GetResponseAsString(&xml); | 536 source->GetResponseAsString(&xml); |
| 537 url_fetcher_.reset(); |
535 ParseManifest(xml); | 538 ParseManifest(xml); |
536 } else { | 539 } else { |
| 540 url_fetcher_.reset(); |
537 CrxUpdateService::OnParseUpdateManifestFailed("network error"); | 541 CrxUpdateService::OnParseUpdateManifestFailed("network error"); |
538 } | 542 } |
539 url_fetcher_.reset(); | |
540 } | 543 } |
541 | 544 |
542 // Parsing the manifest is either done right now for tests or in a sandboxed | 545 // Parsing the manifest is either done right now for tests or in a sandboxed |
543 // process for the production environment. This mitigates the case where an | 546 // process for the production environment. This mitigates the case where an |
544 // attacker was able to feed us a malicious xml string. | 547 // attacker was able to feed us a malicious xml string. |
545 void CrxUpdateService::ParseManifest(const std::string& xml) { | 548 void CrxUpdateService::ParseManifest(const std::string& xml) { |
546 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 549 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
547 if (config_->InProcess()) { | 550 if (config_->InProcess()) { |
548 UpdateManifest manifest; | 551 UpdateManifest manifest; |
549 if (!manifest.Parse(xml)) { | 552 if (!manifest.Parse(xml)) { |
(...skipping 20 matching lines...) Expand all Loading... |
570 std::vector<UpdateManifest::Result>::const_iterator it; | 573 std::vector<UpdateManifest::Result>::const_iterator it; |
571 for (it = results.list.begin(); it != results.list.end(); ++it) { | 574 for (it = results.list.begin(); it != results.list.end(); ++it) { |
572 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id); | 575 CrxUpdateItem* crx = FindUpdateItemById(it->extension_id); |
573 if (!crx) | 576 if (!crx) |
574 continue; | 577 continue; |
575 | 578 |
576 if (crx->status != CrxUpdateItem::kChecking) | 579 if (crx->status != CrxUpdateItem::kChecking) |
577 continue; // Not updating this component now. | 580 continue; // Not updating this component now. |
578 | 581 |
579 if (it->version.empty()) { | 582 if (it->version.empty()) { |
| 583 // No version means no update available. |
580 crx->status = CrxUpdateItem::kNoUpdate; | 584 crx->status = CrxUpdateItem::kNoUpdate; |
581 continue; // No version means no update available. | 585 continue; |
582 } | 586 } |
583 if (!IsVersionNewer(crx->component.version, it->version)) { | 587 if (!IsVersionNewer(crx->component.version, it->version)) { |
| 588 // Our component is up to date. |
584 crx->status = CrxUpdateItem::kUpToDate; | 589 crx->status = CrxUpdateItem::kUpToDate; |
585 continue; // Our component is up to date. | 590 continue; |
586 } | 591 } |
587 if (!it->browser_min_version.empty()) { | 592 if (!it->browser_min_version.empty()) { |
588 if (IsVersionNewer(chrome_version_, it->browser_min_version)) | 593 if (IsVersionNewer(chrome_version_, it->browser_min_version)) { |
589 continue; // Does not apply for this version. | 594 // Does not apply for this chrome version. |
| 595 crx->status = CrxUpdateItem::kNoUpdate; |
| 596 continue; |
| 597 } |
590 } | 598 } |
591 // All test passed. Queue an upgrade for this component and fire the | 599 // All test passed. Queue an upgrade for this component and fire the |
592 // notifications. | 600 // notifications. |
593 crx->crx_url = it->crx_url; | 601 crx->crx_url = it->crx_url; |
594 crx->status = CrxUpdateItem::kCanUpdate; | 602 crx->status = CrxUpdateItem::kCanUpdate; |
595 ++update_pending; | 603 ++update_pending; |
596 | 604 |
597 NotificationService::current()->Notify( | 605 NotificationService::current()->Notify( |
598 chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, | 606 chrome::NOTIFICATION_COMPONENT_UPDATE_FOUND, |
599 Source<std::string>(&crx->id), | 607 Source<std::string>(&crx->id), |
600 NotificationService::NoDetails()); | 608 NotificationService::NoDetails()); |
601 } | 609 } |
| 610 |
| 611 // All the components that are not mentioned in the manifest we |
| 612 // consider them up to date. |
| 613 ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate); |
| 614 |
602 // If there are updates pending we do a short wait. | 615 // If there are updates pending we do a short wait. |
603 ScheduleNextRun(update_pending ? true : false); | 616 ScheduleNextRun(update_pending ? true : false); |
604 } | 617 } |
605 | 618 |
606 void CrxUpdateService::OnParseUpdateManifestFailed( | 619 void CrxUpdateService::OnParseUpdateManifestFailed( |
607 const std::string& error_message) { | 620 const std::string& error_message) { |
608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 621 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
609 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking, | 622 size_t count = ChangeItemStatus(CrxUpdateItem::kChecking, |
610 CrxUpdateItem::kNoUpdate); | 623 CrxUpdateItem::kNoUpdate); |
611 DCHECK_GT(count, 0ul); | 624 DCHECK_GT(count, 0ul); |
612 ScheduleNextRun(false); | 625 ScheduleNextRun(false); |
613 } | 626 } |
614 | 627 |
615 // Called when the CRX package has been downloaded to a temporary location. | 628 // Called when the CRX package has been downloaded to a temporary location. |
616 // Here we fire the notifications and schedule the component-specific installer | 629 // Here we fire the notifications and schedule the component-specific installer |
617 // to be called in the file thread. | 630 // to be called in the file thread. |
618 void CrxUpdateService::OnURLFetchComplete(const URLFetcher* source, | 631 void CrxUpdateService::OnURLFetchComplete(const URLFetcher* source, |
619 CRXContext* context) { | 632 CRXContext* context) { |
620 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 633 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
621 base::PlatformFileError error_code; | 634 base::PlatformFileError error_code; |
622 | 635 |
623 if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) { | 636 if (source->FileErrorOccurred(&error_code) || !FetchSuccess(*source)) { |
624 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading, | 637 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading, |
625 CrxUpdateItem::kNoUpdate); | 638 CrxUpdateItem::kNoUpdate); |
626 DCHECK_EQ(count, 1ul); | 639 DCHECK_EQ(count, 1ul); |
| 640 url_fetcher_.reset(); |
627 ScheduleNextRun(false); | 641 ScheduleNextRun(false); |
628 } else { | 642 } else { |
629 FilePath temp_crx_path; | 643 FilePath temp_crx_path; |
630 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path)); | 644 CHECK(source->GetResponseAsFilePath(true, &temp_crx_path)); |
631 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading, | 645 size_t count = ChangeItemStatus(CrxUpdateItem::kDownloading, |
632 CrxUpdateItem::kUpdating); | 646 CrxUpdateItem::kUpdating); |
633 DCHECK_EQ(count, 1ul); | 647 DCHECK_EQ(count, 1ul); |
| 648 url_fetcher_.reset(); |
| 649 |
634 NotificationService::current()->Notify( | 650 NotificationService::current()->Notify( |
635 chrome::NOTIFICATION_COMPONENT_UPDATE_READY, | 651 chrome::NOTIFICATION_COMPONENT_UPDATE_READY, |
636 Source<std::string>(&context->id), | 652 Source<std::string>(&context->id), |
637 NotificationService::NoDetails()); | 653 NotificationService::NoDetails()); |
638 | 654 |
639 BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, | 655 BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, |
640 NewRunnableMethod(this, &CrxUpdateService::Install, | 656 NewRunnableMethod(this, &CrxUpdateService::Install, |
641 context, | 657 context, |
642 temp_crx_path), | 658 temp_crx_path), |
643 config_->StepDelay()); | 659 config_->StepDelay()); |
644 } | 660 } |
645 | |
646 url_fetcher_.reset(); | |
647 } | 661 } |
648 | 662 |
649 // Install consists of digital signature verification, unpacking and then | 663 // Install consists of digital signature verification, unpacking and then |
650 // calling the component specific installer. All that is handled by the | 664 // calling the component specific installer. All that is handled by the |
651 // |unpacker|. If there is an error this function is in charge of deleting | 665 // |unpacker|. If there is an error this function is in charge of deleting |
652 // the files created. | 666 // the files created. |
653 void CrxUpdateService::Install(const CRXContext* context, | 667 void CrxUpdateService::Install(const CRXContext* context, |
654 const FilePath& crx_path) { | 668 const FilePath& crx_path) { |
655 // This function owns the |crx_path| and the |context| object. | 669 // This function owns the |crx_path| and the |context| object. |
656 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 670 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
(...skipping 23 matching lines...) Expand all Loading... |
680 } | 694 } |
681 | 695 |
682 // The component update factory. Using the component updater as a singleton | 696 // The component update factory. Using the component updater as a singleton |
683 // is the job of the browser process. | 697 // is the job of the browser process. |
684 ComponentUpdateService* ComponentUpdateServiceFactory( | 698 ComponentUpdateService* ComponentUpdateServiceFactory( |
685 ComponentUpdateService::Configurator* config) { | 699 ComponentUpdateService::Configurator* config) { |
686 DCHECK(config); | 700 DCHECK(config); |
687 return new CrxUpdateService(config); | 701 return new CrxUpdateService(config); |
688 } | 702 } |
689 | 703 |
OLD | NEW |