| 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 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/files/file_enumerator.h" |
| 12 #include "base/files/file_util.h" |
| 11 #include "base/logging.h" | 13 #include "base/logging.h" |
| 12 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 13 #include "base/prefs/pref_service.h" | 15 #include "base/prefs/pref_service.h" |
| 14 #include "base/rand_util.h" | 16 #include "base/rand_util.h" |
| 15 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
| 16 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 17 #include "base/strings/string_split.h" | 19 #include "base/strings/string_split.h" |
| 18 #include "chrome/browser/chrome_notification_types.h" | 20 #include "chrome/browser/chrome_notification_types.h" |
| 19 #include "chrome/browser/extensions/api/module/module.h" | 21 #include "chrome/browser/extensions/api/module/module.h" |
| 20 #include "chrome/browser/extensions/crx_installer.h" | 22 #include "chrome/browser/extensions/crx_installer.h" |
| 21 #include "chrome/browser/extensions/extension_service.h" | 23 #include "chrome/browser/extensions/extension_service.h" |
| 22 #include "chrome/browser/extensions/pending_extension_manager.h" | 24 #include "chrome/browser/extensions/pending_extension_manager.h" |
| 23 #include "chrome/browser/profiles/profile.h" | 25 #include "chrome/browser/profiles/profile.h" |
| 24 #include "chrome/common/pref_names.h" | 26 #include "chrome/common/pref_names.h" |
| 27 #include "components/omaha_query_params/omaha_query_params.h" |
| 25 #include "content/public/browser/browser_thread.h" | 28 #include "content/public/browser/browser_thread.h" |
| 26 #include "content/public/browser/notification_details.h" | 29 #include "content/public/browser/notification_details.h" |
| 27 #include "content/public/browser/notification_service.h" | 30 #include "content/public/browser/notification_service.h" |
| 28 #include "content/public/browser/notification_source.h" | 31 #include "content/public/browser/notification_source.h" |
| 29 #include "crypto/sha2.h" | 32 #include "crypto/sha2.h" |
| 30 #include "extensions/browser/extension_prefs.h" | 33 #include "extensions/browser/extension_prefs.h" |
| 31 #include "extensions/browser/extension_registry.h" | 34 #include "extensions/browser/extension_registry.h" |
| 32 #include "extensions/browser/pref_names.h" | 35 #include "extensions/browser/pref_names.h" |
| 33 #include "extensions/common/constants.h" | 36 #include "extensions/common/constants.h" |
| 34 #include "extensions/common/extension.h" | 37 #include "extensions/common/extension.h" |
| 35 #include "extensions/common/extension_set.h" | 38 #include "extensions/common/extension_set.h" |
| 36 #include "extensions/common/manifest.h" | 39 #include "extensions/common/manifest.h" |
| 37 | 40 |
| 38 using base::RandDouble; | 41 using base::RandDouble; |
| 39 using base::RandInt; | 42 using base::RandInt; |
| 40 using base::Time; | 43 using base::Time; |
| 41 using base::TimeDelta; | 44 using base::TimeDelta; |
| 42 using content::BrowserThread; | 45 using content::BrowserThread; |
| 46 using extensions::Extension; |
| 47 using extensions::ExtensionSet; |
| 48 using omaha_query_params::OmahaQueryParams; |
| 43 | 49 |
| 44 typedef extensions::ExtensionDownloaderDelegate::Error Error; | 50 typedef extensions::ExtensionDownloaderDelegate::Error Error; |
| 45 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult; | 51 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult; |
| 46 | 52 |
| 47 namespace { | 53 namespace { |
| 48 | 54 |
| 49 // Wait at least 5 minutes after browser startup before we do any checks. If you | 55 // Wait at least 5 minutes after browser startup before we do any checks. If you |
| 50 // change this value, make sure to update comments where it is used. | 56 // change this value, make sure to update comments where it is used. |
| 51 const int kStartupWaitSeconds = 60 * 5; | 57 const int kStartupWaitSeconds = 60 * 5; |
| 52 | 58 |
| 53 // For sanity checking on update frequency - enforced in release mode only. | 59 // For sanity checking on update frequency - enforced in release mode only. |
| 54 #if defined(NDEBUG) | 60 #if defined(NDEBUG) |
| 55 const int kMinUpdateFrequencySeconds = 30; | 61 const int kMinUpdateFrequencySeconds = 30; |
| 56 #endif | 62 #endif |
| 57 const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days | 63 const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days |
| 58 | 64 |
| 59 // Require at least 5 seconds between consecutive non-succesful extension update | 65 // Require at least 5 seconds between consecutive non-succesful extension update |
| 60 // checks. | 66 // checks. |
| 61 const int kMinUpdateThrottleTime = 5; | 67 const int kMinUpdateThrottleTime = 5; |
| 62 | 68 |
| 69 // The installsource query parameter to use when forcing updates due to NaCl |
| 70 // arch mismatch. |
| 71 const char kWrongMultiCrxInstallSource[] = "wrong_multi_crx"; |
| 72 |
| 63 // When we've computed a days value, we want to make sure we don't send a | 73 // When we've computed a days value, we want to make sure we don't send a |
| 64 // negative value (due to the system clock being set backwards, etc.), since -1 | 74 // negative value (due to the system clock being set backwards, etc.), since -1 |
| 65 // is a special sentinel value that means "never pinged", and other negative | 75 // is a special sentinel value that means "never pinged", and other negative |
| 66 // values don't make sense. | 76 // values don't make sense. |
| 67 int SanitizeDays(int days) { | 77 int SanitizeDays(int days) { |
| 68 if (days < 0) | 78 if (days < 0) |
| 69 return 0; | 79 return 0; |
| 70 return days; | 80 return days; |
| 71 } | 81 } |
| 72 | 82 |
| 73 // Calculates the value to use for the ping days parameter. | 83 // Calculates the value to use for the ping days parameter. |
| 74 int CalculatePingDays(const Time& last_ping_day) { | 84 int CalculatePingDays(const Time& last_ping_day) { |
| 75 int days = extensions::ManifestFetchData::kNeverPinged; | 85 int days = extensions::ManifestFetchData::kNeverPinged; |
| 76 if (!last_ping_day.is_null()) { | 86 if (!last_ping_day.is_null()) { |
| 77 days = SanitizeDays((Time::Now() - last_ping_day).InDays()); | 87 days = SanitizeDays((Time::Now() - last_ping_day).InDays()); |
| 78 } | 88 } |
| 79 return days; | 89 return days; |
| 80 } | 90 } |
| 81 | 91 |
| 82 int CalculateActivePingDays(const Time& last_active_ping_day, | 92 int CalculateActivePingDays(const Time& last_active_ping_day, |
| 83 bool hasActiveBit) { | 93 bool hasActiveBit) { |
| 84 if (!hasActiveBit) | 94 if (!hasActiveBit) |
| 85 return 0; | 95 return 0; |
| 86 if (last_active_ping_day.is_null()) | 96 if (last_active_ping_day.is_null()) |
| 87 return extensions::ManifestFetchData::kNeverPinged; | 97 return extensions::ManifestFetchData::kNeverPinged; |
| 88 return SanitizeDays((Time::Now() - last_active_ping_day).InDays()); | 98 return SanitizeDays((Time::Now() - last_active_ping_day).InDays()); |
| 89 } | 99 } |
| 90 | 100 |
| 101 void RespondWithForcedUpdates( |
| 102 const base::Callback<void(const std::set<std::string>&)>& callback, |
| 103 scoped_ptr<std::set<std::string> > forced_updates) { |
| 104 callback.Run(*forced_updates.get()); |
| 105 } |
| 106 |
| 107 void DetermineForcedUpdatesOnBlockingPool( |
| 108 scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions, |
| 109 const base::Callback<void(const std::set<std::string>&)>& callback) { |
| 110 scoped_ptr<std::set<std::string> > forced_updates( |
| 111 new std::set<std::string>()); |
| 112 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 113 for (std::vector<scoped_refptr<const Extension> >::const_iterator iter = |
| 114 extensions->begin(); |
| 115 iter != extensions->end(); |
| 116 ++iter) { |
| 117 scoped_refptr<const Extension> extension = *iter; |
| 118 base::FilePath platform_specific_path = extension->path().Append( |
| 119 extensions::kPlatformSpecificFolder); |
| 120 if (base::PathExists(platform_specific_path)) { |
| 121 bool force = true; |
| 122 base::FileEnumerator all_archs(platform_specific_path, |
| 123 false, |
| 124 base::FileEnumerator::DIRECTORIES); |
| 125 base::FilePath arch; |
| 126 while (!(arch = all_archs.Next()).empty()) { |
| 127 std::string arch_name = arch.BaseName().AsUTF8Unsafe(); |
| 128 std::replace(arch_name.begin(), arch_name.end(), '_', '-'); |
| 129 if (arch_name == OmahaQueryParams::GetNaclArch()) |
| 130 force = false; |
| 131 } |
| 132 |
| 133 if (force) |
| 134 forced_updates->insert(extension->id()); |
| 135 } |
| 136 } |
| 137 BrowserThread::PostTask( |
| 138 BrowserThread::UI, |
| 139 FROM_HERE, |
| 140 base::Bind(&RespondWithForcedUpdates, |
| 141 callback, |
| 142 base::Passed(&forced_updates))); |
| 143 } |
| 144 |
| 145 void CollectExtensionsFromSet( |
| 146 const ExtensionSet& extensions, |
| 147 std::vector<scoped_refptr<const Extension> >* paths) { |
| 148 std::copy(extensions.begin(), extensions.end(), std::back_inserter(*paths)); |
| 149 } |
| 150 |
| 151 void DetermineForcedUpdates( |
| 152 content::BrowserContext* browser_context, |
| 153 const base::Callback<void(const std::set<std::string>&)>& callback) { |
| 154 scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions( |
| 155 new std::vector<scoped_refptr<const Extension> >()); |
| 156 const extensions::ExtensionRegistry* registry = |
| 157 extensions::ExtensionRegistry::Get(browser_context); |
| 158 scoped_ptr<ExtensionSet> installed_extensions = |
| 159 registry->GenerateInstalledExtensionsSet(); |
| 160 CollectExtensionsFromSet(*installed_extensions.get(), extensions.get()); |
| 161 BrowserThread::PostBlockingPoolTask( |
| 162 FROM_HERE, |
| 163 base::Bind(&DetermineForcedUpdatesOnBlockingPool, |
| 164 base::Passed(&extensions), |
| 165 callback)); |
| 166 } |
| 167 |
| 91 } // namespace | 168 } // namespace |
| 92 | 169 |
| 93 namespace extensions { | 170 namespace extensions { |
| 94 | 171 |
| 95 ExtensionUpdater::CheckParams::CheckParams() | 172 ExtensionUpdater::CheckParams::CheckParams() |
| 96 : install_immediately(false) {} | 173 : install_immediately(false) {} |
| 97 | 174 |
| 98 ExtensionUpdater::CheckParams::~CheckParams() {} | 175 ExtensionUpdater::CheckParams::~CheckParams() {} |
| 99 | 176 |
| 100 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile( | 177 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile( |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 std::list<std::string>::const_iterator pending_id_iter = std::find( | 405 std::list<std::string>::const_iterator pending_id_iter = std::find( |
| 329 pending_ids.begin(), pending_ids.end(), extension.id()); | 406 pending_ids.begin(), pending_ids.end(), extension.id()); |
| 330 if (pending_id_iter == pending_ids.end()) { | 407 if (pending_id_iter == pending_ids.end()) { |
| 331 if (downloader_->AddExtension(extension, request_id)) | 408 if (downloader_->AddExtension(extension, request_id)) |
| 332 request.in_progress_ids_.push_back(extension.id()); | 409 request.in_progress_ids_.push_back(extension.id()); |
| 333 } | 410 } |
| 334 } | 411 } |
| 335 } | 412 } |
| 336 | 413 |
| 337 void ExtensionUpdater::CheckNow(const CheckParams& params) { | 414 void ExtensionUpdater::CheckNow(const CheckParams& params) { |
| 415 DetermineForcedUpdates( |
| 416 profile_, |
| 417 base::Bind(&ExtensionUpdater::OnForcedUpdatesDetermined, |
| 418 weak_ptr_factory_.GetWeakPtr(), |
| 419 params)); |
| 420 } |
| 421 |
| 422 void ExtensionUpdater::OnForcedUpdatesDetermined( |
| 423 const CheckParams& params, |
| 424 const std::set<std::string>& forced_updates) { |
| 338 int request_id = next_request_id_++; | 425 int request_id = next_request_id_++; |
| 339 | 426 |
| 340 VLOG(2) << "Starting update check " << request_id; | 427 VLOG(2) << "Starting update check " << request_id; |
| 341 if (params.ids.empty()) | 428 if (params.ids.empty()) |
| 342 NotifyStarted(); | 429 NotifyStarted(); |
| 343 | 430 |
| 344 DCHECK(alive_); | 431 DCHECK(alive_); |
| 345 | 432 |
| 346 InProgressCheck& request = requests_in_progress_[request_id]; | 433 InProgressCheck& request = requests_in_progress_[request_id]; |
| 347 request.callback = params.callback; | 434 request.callback = params.callback; |
| 348 request.install_immediately = params.install_immediately; | 435 request.install_immediately = params.install_immediately; |
| 349 | 436 |
| 350 EnsureDownloaderCreated(); | 437 EnsureDownloaderCreated(); |
| 351 | 438 |
| 439 forced_updates_ = forced_updates; |
| 440 |
| 352 // Add fetch records for extensions that should be fetched by an update URL. | 441 // Add fetch records for extensions that should be fetched by an update URL. |
| 353 // These extensions are not yet installed. They come from group policy | 442 // These extensions are not yet installed. They come from group policy |
| 354 // and external install sources. | 443 // and external install sources. |
| 355 const PendingExtensionManager* pending_extension_manager = | 444 const PendingExtensionManager* pending_extension_manager = |
| 356 service_->pending_extension_manager(); | 445 service_->pending_extension_manager(); |
| 357 | 446 |
| 358 std::list<std::string> pending_ids; | 447 std::list<std::string> pending_ids; |
| 359 | 448 |
| 360 if (params.ids.empty()) { | 449 if (params.ids.empty()) { |
| 361 // If no extension ids are specified, check for updates for all extensions. | 450 // If no extension ids are specified, check for updates for all extensions. |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 if (!extension) | 618 if (!extension) |
| 530 return false; | 619 return false; |
| 531 const Extension* update = service_->GetPendingExtensionUpdate(id); | 620 const Extension* update = service_->GetPendingExtensionUpdate(id); |
| 532 if (update) | 621 if (update) |
| 533 *version = update->VersionString(); | 622 *version = update->VersionString(); |
| 534 else | 623 else |
| 535 *version = extension->VersionString(); | 624 *version = extension->VersionString(); |
| 536 return true; | 625 return true; |
| 537 } | 626 } |
| 538 | 627 |
| 628 bool ExtensionUpdater::ShouldForceUpdate( |
| 629 const std::string& extension_id, |
| 630 std::string* source) { |
| 631 bool force = forced_updates_.find(extension_id) != forced_updates_.end(); |
| 632 // Currently the only reason to force is a NaCl arch mismatch with the |
| 633 // installed extension contents. |
| 634 if (force) { |
| 635 *source = kWrongMultiCrxInstallSource; |
| 636 } |
| 637 return force; |
| 638 } |
| 639 |
| 539 void ExtensionUpdater::UpdatePingData(const std::string& id, | 640 void ExtensionUpdater::UpdatePingData(const std::string& id, |
| 540 const PingResult& ping_result) { | 641 const PingResult& ping_result) { |
| 541 DCHECK(alive_); | 642 DCHECK(alive_); |
| 542 if (ping_result.did_ping) | 643 if (ping_result.did_ping) |
| 543 extension_prefs_->SetLastPingDay(id, ping_result.day_start); | 644 extension_prefs_->SetLastPingDay(id, ping_result.day_start); |
| 544 if (extension_prefs_->GetActiveBit(id)) { | 645 if (extension_prefs_->GetActiveBit(id)) { |
| 545 extension_prefs_->SetActiveBit(id, false); | 646 extension_prefs_->SetActiveBit(id, false); |
| 546 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start); | 647 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start); |
| 547 } | 648 } |
| 548 } | 649 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 const InProgressCheck& request = requests_in_progress_[request_id]; | 743 const InProgressCheck& request = requests_in_progress_[request_id]; |
| 643 if (request.in_progress_ids_.empty()) { | 744 if (request.in_progress_ids_.empty()) { |
| 644 VLOG(2) << "Finished update check " << request_id; | 745 VLOG(2) << "Finished update check " << request_id; |
| 645 if (!request.callback.is_null()) | 746 if (!request.callback.is_null()) |
| 646 request.callback.Run(); | 747 request.callback.Run(); |
| 647 requests_in_progress_.erase(request_id); | 748 requests_in_progress_.erase(request_id); |
| 648 } | 749 } |
| 649 } | 750 } |
| 650 | 751 |
| 651 } // namespace extensions | 752 } // namespace extensions |
| OLD | NEW |