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 |