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) { | |
Yoyo Zhou
2014/09/04 22:41:26
Consider DCHECKing that we're on a non-UI thread.
Ken Rockot(use gerrit already)
2014/09/05 01:41:34
Done.
| |
110 scoped_ptr<std::set<std::string> > forced_updates( | |
111 new std::set<std::string>()); | |
112 for (std::vector<scoped_refptr<const Extension> >::const_iterator iter = | |
113 extensions->begin(); | |
114 iter != extensions->end(); | |
115 ++iter) { | |
116 scoped_refptr<const Extension> extension = *iter; | |
117 base::FilePath platform_specific_path = extension->path().Append( | |
118 extensions::kPlatformSpecificFolder); | |
119 if (base::PathExists(platform_specific_path)) { | |
120 bool force = true; | |
121 base::FileEnumerator all_archs(platform_specific_path, | |
122 false, | |
123 base::FileEnumerator::DIRECTORIES); | |
124 base::FilePath arch; | |
125 while (!(arch = all_archs.Next()).empty()) { | |
126 std::string arch_name = arch.BaseName().AsUTF8Unsafe(); | |
127 std::replace(arch_name.begin(), arch_name.end(), '_', '-'); | |
128 if (arch_name == OmahaQueryParams::GetNaclArch()) | |
129 force = false; | |
130 } | |
131 | |
132 if (force) | |
133 forced_updates->insert(extension->id()); | |
134 } | |
135 } | |
136 BrowserThread::PostTask( | |
137 BrowserThread::UI, | |
138 FROM_HERE, | |
139 base::Bind(&RespondWithForcedUpdates, | |
140 callback, | |
141 base::Passed(&forced_updates))); | |
142 } | |
143 | |
144 void CollectExtensionsFromSet( | |
145 const ExtensionSet& extensions, | |
146 std::vector<scoped_refptr<const Extension> >* paths) { | |
147 std::copy(extensions.begin(), extensions.end(), std::back_inserter(*paths)); | |
148 } | |
149 | |
150 void DetermineForcedUpdates( | |
151 content::BrowserContext* browser_context, | |
152 const base::Callback<void(const std::set<std::string>&)>& callback) { | |
153 scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions( | |
154 new std::vector<scoped_refptr<const Extension> >()); | |
155 const extensions::ExtensionRegistry* registry = | |
156 extensions::ExtensionRegistry::Get(browser_context); | |
157 CollectExtensionsFromSet(registry->enabled_extensions(), extensions.get()); | |
Yoyo Zhou
2014/09/04 22:41:26
Why not use registry->GenerateInstalledExtensionsS
Ken Rockot(use gerrit already)
2014/09/05 01:41:34
Because I totally missed it when looking over the
| |
158 CollectExtensionsFromSet(registry->disabled_extensions(), extensions.get()); | |
159 BrowserThread::PostBlockingPoolTask( | |
160 FROM_HERE, | |
161 base::Bind(&DetermineForcedUpdatesOnBlockingPool, | |
162 base::Passed(&extensions), | |
163 callback)); | |
164 } | |
165 | |
91 } // namespace | 166 } // namespace |
92 | 167 |
93 namespace extensions { | 168 namespace extensions { |
94 | 169 |
95 ExtensionUpdater::CheckParams::CheckParams() | 170 ExtensionUpdater::CheckParams::CheckParams() |
96 : install_immediately(false) {} | 171 : install_immediately(false) {} |
97 | 172 |
98 ExtensionUpdater::CheckParams::~CheckParams() {} | 173 ExtensionUpdater::CheckParams::~CheckParams() {} |
99 | 174 |
100 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile( | 175 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( | 403 std::list<std::string>::const_iterator pending_id_iter = std::find( |
329 pending_ids.begin(), pending_ids.end(), extension.id()); | 404 pending_ids.begin(), pending_ids.end(), extension.id()); |
330 if (pending_id_iter == pending_ids.end()) { | 405 if (pending_id_iter == pending_ids.end()) { |
331 if (downloader_->AddExtension(extension, request_id)) | 406 if (downloader_->AddExtension(extension, request_id)) |
332 request.in_progress_ids_.push_back(extension.id()); | 407 request.in_progress_ids_.push_back(extension.id()); |
333 } | 408 } |
334 } | 409 } |
335 } | 410 } |
336 | 411 |
337 void ExtensionUpdater::CheckNow(const CheckParams& params) { | 412 void ExtensionUpdater::CheckNow(const CheckParams& params) { |
413 DetermineForcedUpdates( | |
414 profile_, | |
415 base::Bind(&ExtensionUpdater::OnForcedUpdatesDetermined, | |
416 weak_ptr_factory_.GetWeakPtr(), | |
417 params)); | |
418 } | |
419 | |
420 void ExtensionUpdater::OnForcedUpdatesDetermined( | |
421 const CheckParams& params, | |
422 const std::set<std::string>& forced_updates) { | |
338 int request_id = next_request_id_++; | 423 int request_id = next_request_id_++; |
339 | 424 |
340 VLOG(2) << "Starting update check " << request_id; | 425 VLOG(2) << "Starting update check " << request_id; |
341 if (params.ids.empty()) | 426 if (params.ids.empty()) |
342 NotifyStarted(); | 427 NotifyStarted(); |
343 | 428 |
344 DCHECK(alive_); | 429 DCHECK(alive_); |
345 | 430 |
346 InProgressCheck& request = requests_in_progress_[request_id]; | 431 InProgressCheck& request = requests_in_progress_[request_id]; |
347 request.callback = params.callback; | 432 request.callback = params.callback; |
348 request.install_immediately = params.install_immediately; | 433 request.install_immediately = params.install_immediately; |
349 | 434 |
350 EnsureDownloaderCreated(); | 435 EnsureDownloaderCreated(); |
351 | 436 |
437 forced_updates_ = forced_updates; | |
438 | |
352 // Add fetch records for extensions that should be fetched by an update URL. | 439 // 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 | 440 // These extensions are not yet installed. They come from group policy |
354 // and external install sources. | 441 // and external install sources. |
355 const PendingExtensionManager* pending_extension_manager = | 442 const PendingExtensionManager* pending_extension_manager = |
356 service_->pending_extension_manager(); | 443 service_->pending_extension_manager(); |
357 | 444 |
358 std::list<std::string> pending_ids; | 445 std::list<std::string> pending_ids; |
359 | 446 |
360 if (params.ids.empty()) { | 447 if (params.ids.empty()) { |
361 // If no extension ids are specified, check for updates for all extensions. | 448 // 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) | 616 if (!extension) |
530 return false; | 617 return false; |
531 const Extension* update = service_->GetPendingExtensionUpdate(id); | 618 const Extension* update = service_->GetPendingExtensionUpdate(id); |
532 if (update) | 619 if (update) |
533 *version = update->VersionString(); | 620 *version = update->VersionString(); |
534 else | 621 else |
535 *version = extension->VersionString(); | 622 *version = extension->VersionString(); |
536 return true; | 623 return true; |
537 } | 624 } |
538 | 625 |
626 bool ExtensionUpdater::ShouldForceUpdate( | |
627 const std::string& extension_id, | |
628 std::string* source) { | |
629 bool force = forced_updates_.find(extension_id) != forced_updates_.end(); | |
630 // Currently the only reason to force is a NaCl arch mismatch with the | |
631 // installed extension contents. | |
632 if (force) { | |
633 *source = kWrongMultiCrxInstallSource; | |
634 } | |
635 return force; | |
636 } | |
637 | |
539 void ExtensionUpdater::UpdatePingData(const std::string& id, | 638 void ExtensionUpdater::UpdatePingData(const std::string& id, |
540 const PingResult& ping_result) { | 639 const PingResult& ping_result) { |
541 DCHECK(alive_); | 640 DCHECK(alive_); |
542 if (ping_result.did_ping) | 641 if (ping_result.did_ping) |
543 extension_prefs_->SetLastPingDay(id, ping_result.day_start); | 642 extension_prefs_->SetLastPingDay(id, ping_result.day_start); |
544 if (extension_prefs_->GetActiveBit(id)) { | 643 if (extension_prefs_->GetActiveBit(id)) { |
545 extension_prefs_->SetActiveBit(id, false); | 644 extension_prefs_->SetActiveBit(id, false); |
546 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start); | 645 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start); |
547 } | 646 } |
548 } | 647 } |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
642 const InProgressCheck& request = requests_in_progress_[request_id]; | 741 const InProgressCheck& request = requests_in_progress_[request_id]; |
643 if (request.in_progress_ids_.empty()) { | 742 if (request.in_progress_ids_.empty()) { |
644 VLOG(2) << "Finished update check " << request_id; | 743 VLOG(2) << "Finished update check " << request_id; |
645 if (!request.callback.is_null()) | 744 if (!request.callback.is_null()) |
646 request.callback.Run(); | 745 request.callback.Run(); |
647 requests_in_progress_.erase(request_id); | 746 requests_in_progress_.erase(request_id); |
648 } | 747 } |
649 } | 748 } |
650 | 749 |
651 } // namespace extensions | 750 } // namespace extensions |
OLD | NEW |