| 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/extensions/updater/extension_updater.h" | 5 #include "chrome/browser/extensions/updater/extension_updater.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
| 14 #include "base/prefs/pref_service.h" | 14 #include "base/prefs/pref_service.h" |
| 15 #include "base/rand_util.h" | 15 #include "base/rand_util.h" |
| 16 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
| 17 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/strings/string_split.h" | 18 #include "base/strings/string_split.h" |
| 19 #include "chrome/browser/chrome_notification_types.h" | 19 #include "chrome/browser/chrome_notification_types.h" |
| 20 #include "chrome/browser/extensions/api/module/module.h" | 20 #include "chrome/browser/extensions/api/module/module.h" |
| 21 #include "chrome/browser/extensions/blacklist.h" | |
| 22 #include "chrome/browser/extensions/crx_installer.h" | 21 #include "chrome/browser/extensions/crx_installer.h" |
| 23 #include "chrome/browser/extensions/extension_service.h" | 22 #include "chrome/browser/extensions/extension_service.h" |
| 24 #include "chrome/browser/extensions/pending_extension_manager.h" | 23 #include "chrome/browser/extensions/pending_extension_manager.h" |
| 25 #include "chrome/browser/extensions/updater/extension_downloader.h" | 24 #include "chrome/browser/extensions/updater/extension_downloader.h" |
| 26 #include "chrome/browser/profiles/profile.h" | 25 #include "chrome/browser/profiles/profile.h" |
| 27 #include "chrome/common/extensions/extension.h" | 26 #include "chrome/common/extensions/extension.h" |
| 28 #include "chrome/common/extensions/extension_set.h" | 27 #include "chrome/common/extensions/extension_set.h" |
| 29 #include "chrome/common/pref_names.h" | 28 #include "chrome/common/pref_names.h" |
| 30 #include "content/public/browser/browser_thread.h" | 29 #include "content/public/browser/browser_thread.h" |
| 31 #include "content/public/browser/notification_details.h" | 30 #include "content/public/browser/notification_details.h" |
| 32 #include "content/public/browser/notification_service.h" | 31 #include "content/public/browser/notification_service.h" |
| 33 #include "content/public/browser/notification_source.h" | 32 #include "content/public/browser/notification_source.h" |
| 34 #include "crypto/sha2.h" | 33 #include "crypto/sha2.h" |
| 35 #include "extensions/common/manifest.h" | 34 #include "extensions/common/manifest.h" |
| 36 | 35 |
| 37 using base::RandDouble; | 36 using base::RandDouble; |
| 38 using base::RandInt; | 37 using base::RandInt; |
| 39 using base::Time; | 38 using base::Time; |
| 40 using base::TimeDelta; | 39 using base::TimeDelta; |
| 41 using content::BrowserThread; | 40 using content::BrowserThread; |
| 42 using prefs::kExtensionBlacklistUpdateVersion; | |
| 43 using prefs::kLastExtensionsUpdateCheck; | 41 using prefs::kLastExtensionsUpdateCheck; |
| 44 using prefs::kNextExtensionsUpdateCheck; | 42 using prefs::kNextExtensionsUpdateCheck; |
| 45 | 43 |
| 46 typedef extensions::ExtensionDownloaderDelegate::Error Error; | 44 typedef extensions::ExtensionDownloaderDelegate::Error Error; |
| 47 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult; | 45 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult; |
| 48 | 46 |
| 49 namespace { | 47 namespace { |
| 50 | 48 |
| 51 // Wait at least 5 minutes after browser startup before we do any checks. If you | 49 // Wait at least 5 minutes after browser startup before we do any checks. If you |
| 52 // change this value, make sure to update comments where it is used. | 50 // change this value, make sure to update comments where it is used. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 if (last_active_ping_day.is_null()) | 84 if (last_active_ping_day.is_null()) |
| 87 return extensions::ManifestFetchData::kNeverPinged; | 85 return extensions::ManifestFetchData::kNeverPinged; |
| 88 return SanitizeDays((Time::Now() - last_active_ping_day).InDays()); | 86 return SanitizeDays((Time::Now() - last_active_ping_day).InDays()); |
| 89 } | 87 } |
| 90 | 88 |
| 91 } // namespace | 89 } // namespace |
| 92 | 90 |
| 93 namespace extensions { | 91 namespace extensions { |
| 94 | 92 |
| 95 ExtensionUpdater::CheckParams::CheckParams() | 93 ExtensionUpdater::CheckParams::CheckParams() |
| 96 : check_blacklist(true), install_immediately(false) {} | 94 : install_immediately(false) {} |
| 97 | 95 |
| 98 ExtensionUpdater::CheckParams::~CheckParams() {} | 96 ExtensionUpdater::CheckParams::~CheckParams() {} |
| 99 | 97 |
| 100 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile( | 98 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile( |
| 101 const std::string& i, | 99 const std::string& i, |
| 102 const base::FilePath& p, | 100 const base::FilePath& p, |
| 103 const GURL& u, | 101 const GURL& u, |
| 104 const std::set<int>& request_ids) | 102 const std::set<int>& request_ids) |
| 105 : extension_id(i), | 103 : extension_id(i), |
| 106 path(p), | 104 path(p), |
| (...skipping 17 matching lines...) Expand all Loading... |
| 124 | 122 |
| 125 bool in_progress; | 123 bool in_progress; |
| 126 int throttle_delay; | 124 int throttle_delay; |
| 127 Time check_start; | 125 Time check_start; |
| 128 }; | 126 }; |
| 129 | 127 |
| 130 ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service, | 128 ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service, |
| 131 ExtensionPrefs* extension_prefs, | 129 ExtensionPrefs* extension_prefs, |
| 132 PrefService* prefs, | 130 PrefService* prefs, |
| 133 Profile* profile, | 131 Profile* profile, |
| 134 Blacklist* blacklist, | |
| 135 int frequency_seconds) | 132 int frequency_seconds) |
| 136 : alive_(false), | 133 : alive_(false), |
| 137 weak_ptr_factory_(this), | 134 weak_ptr_factory_(this), |
| 138 service_(service), frequency_seconds_(frequency_seconds), | 135 service_(service), frequency_seconds_(frequency_seconds), |
| 139 will_check_soon_(false), extension_prefs_(extension_prefs), | 136 will_check_soon_(false), extension_prefs_(extension_prefs), |
| 140 prefs_(prefs), profile_(profile), blacklist_(blacklist), | 137 prefs_(prefs), profile_(profile), |
| 141 next_request_id_(0), | 138 next_request_id_(0), |
| 142 crx_install_is_running_(false) { | 139 crx_install_is_running_(false) { |
| 143 DCHECK_GE(frequency_seconds_, 5); | 140 DCHECK_GE(frequency_seconds_, 5); |
| 144 DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds); | 141 DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds); |
| 145 #ifdef NDEBUG | 142 #ifdef NDEBUG |
| 146 // In Release mode we enforce that update checks don't happen too often. | 143 // In Release mode we enforce that update checks don't happen too often. |
| 147 frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds); | 144 frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds); |
| 148 #endif | 145 #endif |
| 149 frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds); | 146 frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds); |
| 150 | 147 |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 } else { | 364 } else { |
| 368 for (std::list<std::string>::const_iterator it = params.ids.begin(); | 365 for (std::list<std::string>::const_iterator it = params.ids.begin(); |
| 369 it != params.ids.end(); ++it) { | 366 it != params.ids.end(); ++it) { |
| 370 const Extension* extension = service_->GetExtensionById(*it, true); | 367 const Extension* extension = service_->GetExtensionById(*it, true); |
| 371 DCHECK(extension); | 368 DCHECK(extension); |
| 372 if (downloader_->AddExtension(*extension, request_id)) | 369 if (downloader_->AddExtension(*extension, request_id)) |
| 373 request.in_progress_ids_.push_back(extension->id()); | 370 request.in_progress_ids_.push_back(extension->id()); |
| 374 } | 371 } |
| 375 } | 372 } |
| 376 | 373 |
| 377 // Start a fetch of the blacklist if needed. | |
| 378 if (params.check_blacklist) { | |
| 379 ManifestFetchData::PingData ping_data; | |
| 380 ping_data.rollcall_days = | |
| 381 CalculatePingDays(extension_prefs_->BlacklistLastPingDay()); | |
| 382 request.in_progress_ids_.push_back(ExtensionDownloader::kBlacklistAppID); | |
| 383 downloader_->StartBlacklistUpdate( | |
| 384 prefs_->GetString(kExtensionBlacklistUpdateVersion), ping_data, | |
| 385 request_id); | |
| 386 } | |
| 387 | |
| 388 // StartAllPending() might call OnExtensionDownloadFailed/Finished before | 374 // StartAllPending() might call OnExtensionDownloadFailed/Finished before |
| 389 // it returns, which would cause NotifyIfFinished to incorrectly try to | 375 // it returns, which would cause NotifyIfFinished to incorrectly try to |
| 390 // send out a notification. So check before we call StartAllPending if any | 376 // send out a notification. So check before we call StartAllPending if any |
| 391 // extensions are going to be updated, and use that to figure out if | 377 // extensions are going to be updated, and use that to figure out if |
| 392 // NotifyIfFinished should be called. | 378 // NotifyIfFinished should be called. |
| 393 bool noChecks = request.in_progress_ids_.empty(); | 379 bool noChecks = request.in_progress_ids_.empty(); |
| 394 | 380 |
| 395 // StartAllPending() will call OnExtensionDownloadFailed or | 381 // StartAllPending() will call OnExtensionDownloadFailed or |
| 396 // OnExtensionDownloadFinished for each extension that was checked. | 382 // OnExtensionDownloadFinished for each extension that was checked. |
| 397 downloader_->StartAllPending(); | 383 downloader_->StartAllPending(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 428 // TODO(mek): Somehow increase time between allowing checks when checks | 414 // TODO(mek): Somehow increase time between allowing checks when checks |
| 429 // are repeatedly throttled and don't result in updates being installed. | 415 // are repeatedly throttled and don't result in updates being installed. |
| 430 | 416 |
| 431 // It's okay to start a check, update values. | 417 // It's okay to start a check, update values. |
| 432 info.check_start = now; | 418 info.check_start = now; |
| 433 info.in_progress = true; | 419 info.in_progress = true; |
| 434 } | 420 } |
| 435 | 421 |
| 436 CheckParams params; | 422 CheckParams params; |
| 437 params.ids.push_back(extension_id); | 423 params.ids.push_back(extension_id); |
| 438 params.check_blacklist = false; | |
| 439 params.callback = base::Bind(&ExtensionUpdater::ExtensionCheckFinished, | 424 params.callback = base::Bind(&ExtensionUpdater::ExtensionCheckFinished, |
| 440 weak_ptr_factory_.GetWeakPtr(), | 425 weak_ptr_factory_.GetWeakPtr(), |
| 441 extension_id, callback); | 426 extension_id, callback); |
| 442 CheckNow(params); | 427 CheckNow(params); |
| 443 return true; | 428 return true; |
| 444 } | 429 } |
| 445 | 430 |
| 446 void ExtensionUpdater::ExtensionCheckFinished( | 431 void ExtensionUpdater::ExtensionCheckFinished( |
| 447 const std::string& extension_id, | 432 const std::string& extension_id, |
| 448 const FinishedCallback& callback) { | 433 const FinishedCallback& callback) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 VLOG(2) << download_url << " written to " << path.value(); | 476 VLOG(2) << download_url << " written to " << path.value(); |
| 492 | 477 |
| 493 FetchedCRXFile fetched(id, path, download_url, request_ids); | 478 FetchedCRXFile fetched(id, path, download_url, request_ids); |
| 494 fetched_crx_files_.push(fetched); | 479 fetched_crx_files_.push(fetched); |
| 495 | 480 |
| 496 // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after | 481 // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after |
| 497 // starting the crx installer. | 482 // starting the crx installer. |
| 498 MaybeInstallCRXFile(); | 483 MaybeInstallCRXFile(); |
| 499 } | 484 } |
| 500 | 485 |
| 501 void ExtensionUpdater::OnBlacklistDownloadFinished( | |
| 502 const std::string& data, | |
| 503 const std::string& package_hash, | |
| 504 const std::string& version, | |
| 505 const PingResult& ping, | |
| 506 const std::set<int>& request_ids) { | |
| 507 DCHECK(alive_); | |
| 508 UpdatePingData(ExtensionDownloader::kBlacklistAppID, ping); | |
| 509 for (std::set<int>::const_iterator it = request_ids.begin(); | |
| 510 it != request_ids.end(); ++it) { | |
| 511 InProgressCheck& request = requests_in_progress_[*it]; | |
| 512 request.in_progress_ids_.remove(ExtensionDownloader::kBlacklistAppID); | |
| 513 NotifyIfFinished(*it); | |
| 514 } | |
| 515 | |
| 516 // Verify sha256 hash value. | |
| 517 char sha256_hash_value[crypto::kSHA256Length]; | |
| 518 crypto::SHA256HashString(data, sha256_hash_value, crypto::kSHA256Length); | |
| 519 std::string hash_in_hex = base::HexEncode(sha256_hash_value, | |
| 520 crypto::kSHA256Length); | |
| 521 | |
| 522 if (package_hash != hash_in_hex) { | |
| 523 NOTREACHED() << "Fetched blacklist checksum is not as expected. " | |
| 524 << "Expected: " << package_hash << " Actual: " << hash_in_hex; | |
| 525 return; | |
| 526 } | |
| 527 std::vector<std::string> blacklist; | |
| 528 base::SplitString(data, '\n', &blacklist); | |
| 529 | |
| 530 blacklist_->SetFromUpdater(blacklist, version); | |
| 531 } | |
| 532 | |
| 533 bool ExtensionUpdater::GetPingDataForExtension( | 486 bool ExtensionUpdater::GetPingDataForExtension( |
| 534 const std::string& id, | 487 const std::string& id, |
| 535 ManifestFetchData::PingData* ping_data) { | 488 ManifestFetchData::PingData* ping_data) { |
| 536 DCHECK(alive_); | 489 DCHECK(alive_); |
| 537 ping_data->rollcall_days = CalculatePingDays( | 490 ping_data->rollcall_days = CalculatePingDays( |
| 538 extension_prefs_->LastPingDay(id)); | 491 extension_prefs_->LastPingDay(id)); |
| 539 ping_data->is_enabled = service_->IsExtensionEnabled(id); | 492 ping_data->is_enabled = service_->IsExtensionEnabled(id); |
| 540 ping_data->active_days = | 493 ping_data->active_days = |
| 541 CalculateActivePingDays(extension_prefs_->LastActivePingDay(id), | 494 CalculateActivePingDays(extension_prefs_->LastActivePingDay(id), |
| 542 extension_prefs_->GetActiveBit(id)); | 495 extension_prefs_->GetActiveBit(id)); |
| 543 return true; | 496 return true; |
| 544 } | 497 } |
| 545 | 498 |
| 546 std::string ExtensionUpdater::GetUpdateUrlData(const std::string& id) { | 499 std::string ExtensionUpdater::GetUpdateUrlData(const std::string& id) { |
| 547 DCHECK(alive_); | 500 DCHECK(alive_); |
| 548 return extension::GetUpdateURLData(extension_prefs_, id); | 501 return extension::GetUpdateURLData(extension_prefs_, id); |
| 549 } | 502 } |
| 550 | 503 |
| 551 bool ExtensionUpdater::IsExtensionPending(const std::string& id) { | 504 bool ExtensionUpdater::IsExtensionPending(const std::string& id) { |
| 552 DCHECK(alive_); | 505 DCHECK(alive_); |
| 553 return service_->pending_extension_manager()->IsIdPending(id); | 506 return service_->pending_extension_manager()->IsIdPending(id); |
| 554 } | 507 } |
| 555 | 508 |
| 556 bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id, | 509 bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id, |
| 557 std::string* version) { | 510 std::string* version) { |
| 558 DCHECK(alive_); | 511 DCHECK(alive_); |
| 559 if (id == ExtensionDownloader::kBlacklistAppID) { | |
| 560 *version = prefs_->GetString(kExtensionBlacklistUpdateVersion); | |
| 561 return true; | |
| 562 } | |
| 563 const Extension* extension = service_->GetExtensionById(id, true); | 512 const Extension* extension = service_->GetExtensionById(id, true); |
| 564 if (!extension) | 513 if (!extension) |
| 565 return false; | 514 return false; |
| 566 const Extension* update = service_->GetPendingExtensionUpdate(id); | 515 const Extension* update = service_->GetPendingExtensionUpdate(id); |
| 567 if (update) | 516 if (update) |
| 568 *version = update->VersionString(); | 517 *version = update->VersionString(); |
| 569 else | 518 else |
| 570 *version = extension->VersionString(); | 519 *version = extension->VersionString(); |
| 571 return true; | 520 return true; |
| 572 } | 521 } |
| 573 | 522 |
| 574 void ExtensionUpdater::UpdatePingData(const std::string& id, | 523 void ExtensionUpdater::UpdatePingData(const std::string& id, |
| 575 const PingResult& ping_result) { | 524 const PingResult& ping_result) { |
| 576 DCHECK(alive_); | 525 DCHECK(alive_); |
| 577 if (ping_result.did_ping) { | 526 if (ping_result.did_ping) |
| 578 if (id == ExtensionDownloader::kBlacklistAppID) { | 527 extension_prefs_->SetLastPingDay(id, ping_result.day_start); |
| 579 extension_prefs_->SetBlacklistLastPingDay(ping_result.day_start); | |
| 580 } else if (service_->GetExtensionById(id, true) != NULL) { | |
| 581 extension_prefs_->SetLastPingDay(id, ping_result.day_start); | |
| 582 } | |
| 583 } | |
| 584 if (extension_prefs_->GetActiveBit(id)) { | 528 if (extension_prefs_->GetActiveBit(id)) { |
| 585 extension_prefs_->SetActiveBit(id, false); | 529 extension_prefs_->SetActiveBit(id, false); |
| 586 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start); | 530 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start); |
| 587 } | 531 } |
| 588 } | 532 } |
| 589 | 533 |
| 590 void ExtensionUpdater::MaybeInstallCRXFile() { | 534 void ExtensionUpdater::MaybeInstallCRXFile() { |
| 591 if (crx_install_is_running_ || fetched_crx_files_.empty()) | 535 if (crx_install_is_running_ || fetched_crx_files_.empty()) |
| 592 return; | 536 return; |
| 593 | 537 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 688 const InProgressCheck& request = requests_in_progress_[request_id]; | 632 const InProgressCheck& request = requests_in_progress_[request_id]; |
| 689 if (request.in_progress_ids_.empty()) { | 633 if (request.in_progress_ids_.empty()) { |
| 690 VLOG(2) << "Finished update check " << request_id; | 634 VLOG(2) << "Finished update check " << request_id; |
| 691 if (!request.callback.is_null()) | 635 if (!request.callback.is_null()) |
| 692 request.callback.Run(); | 636 request.callback.Run(); |
| 693 requests_in_progress_.erase(request_id); | 637 requests_in_progress_.erase(request_id); |
| 694 } | 638 } |
| 695 } | 639 } |
| 696 | 640 |
| 697 } // namespace extensions | 641 } // namespace extensions |
| OLD | NEW |