OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/extensions_service.h" | 5 #include "chrome/browser/extensions/extensions_service.h" |
6 | 6 |
7 #include "app/l10n_util.h" | |
8 #include "base/command_line.h" | 7 #include "base/command_line.h" |
9 #include "base/file_util.h" | 8 #include "base/file_util.h" |
10 #include "base/string_util.h" | 9 #include "base/string_util.h" |
11 #include "base/values.h" | 10 #include "base/values.h" |
12 #include "chrome/browser/browser.h" | 11 #include "chrome/browser/extensions/crx_installer.h" |
13 #include "chrome/browser/browser_list.h" | |
14 #include "chrome/browser/browser_process.h" | |
15 #include "chrome/browser/chrome_thread.h" | |
16 #include "chrome/browser/extensions/extension_browser_event_router.h" | 12 #include "chrome/browser/extensions/extension_browser_event_router.h" |
17 #include "chrome/browser/extensions/extension_file_util.h" | 13 #include "chrome/browser/extensions/extension_file_util.h" |
18 #include "chrome/browser/extensions/extension_process_manager.h" | |
19 #include "chrome/browser/extensions/extension_updater.h" | 14 #include "chrome/browser/extensions/extension_updater.h" |
20 #include "chrome/browser/extensions/external_extension_provider.h" | 15 #include "chrome/browser/extensions/external_extension_provider.h" |
21 #include "chrome/browser/extensions/external_pref_extension_provider.h" | 16 #include "chrome/browser/extensions/external_pref_extension_provider.h" |
22 #include "chrome/browser/extensions/theme_preview_infobar_delegate.h" | 17 #include "chrome/browser/extensions/theme_preview_infobar_delegate.h" |
23 #include "chrome/browser/profile.h" | 18 #include "chrome/browser/profile.h" |
24 #include "chrome/browser/tab_contents/tab_contents.h" | 19 #include "chrome/browser/tab_contents/tab_contents.h" |
25 #include "chrome/common/chrome_switches.h" | 20 #include "chrome/common/chrome_switches.h" |
26 #include "chrome/common/extensions/extension.h" | 21 #include "chrome/common/extensions/extension.h" |
27 #include "chrome/common/extensions/extension_error_reporter.h" | 22 #include "chrome/common/extensions/extension_error_reporter.h" |
28 #include "chrome/common/notification_service.h" | 23 #include "chrome/common/notification_service.h" |
29 #include "chrome/common/pref_names.h" | 24 #include "chrome/common/pref_names.h" |
30 #include "chrome/common/pref_service.h" | 25 #include "chrome/common/pref_service.h" |
31 #include "chrome/common/url_constants.h" | 26 #include "chrome/common/url_constants.h" |
32 #include "grit/chromium_strings.h" | |
33 #include "grit/generated_resources.h" | |
34 | 27 |
35 #if defined(OS_WIN) | 28 #if defined(OS_WIN) |
36 #include "app/win_util.h" | |
37 #include "chrome/browser/extensions/external_registry_extension_provider_win.h" | 29 #include "chrome/browser/extensions/external_registry_extension_provider_win.h" |
38 #elif defined(OS_MACOSX) | |
39 #include "base/scoped_cftyperef.h" | |
40 #include "base/sys_string_conversions.h" | |
41 #include <CoreFoundation/CFUserNotification.h> | |
42 #endif | 30 #endif |
43 | 31 |
44 // ExtensionsService. | 32 // ExtensionsService. |
45 | 33 |
46 const char* ExtensionsService::kInstallDirectoryName = "Extensions"; | 34 const char* ExtensionsService::kInstallDirectoryName = "Extensions"; |
47 const char* ExtensionsService::kCurrentVersionFileName = "Current Version"; | 35 const char* ExtensionsService::kCurrentVersionFileName = "Current Version"; |
48 | 36 |
49 const char* ExtensionsService::kGalleryDownloadURLPrefix = | 37 const char* ExtensionsService::kGalleryDownloadURLPrefix = |
50 "https://dl-ssl.google.com/chrome/"; | 38 "https://dl-ssl.google.com/chrome/"; |
51 const char* ExtensionsService::kGalleryURLPrefix = | 39 const char* ExtensionsService::kGalleryURLPrefix = |
52 "https://tools.google.com/chrome/"; | 40 "https://tools.google.com/chrome/"; |
53 | 41 |
54 // static | 42 // static |
55 bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url, | 43 bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url, |
56 const GURL& referrer_url) { | 44 const GURL& referrer_url) { |
57 if (StartsWithASCII(download_url.spec(), kGalleryDownloadURLPrefix, false) && | 45 if (StartsWithASCII(download_url.spec(), kGalleryDownloadURLPrefix, false) && |
58 StartsWithASCII(referrer_url.spec(), kGalleryURLPrefix, false)) { | 46 StartsWithASCII(referrer_url.spec(), kGalleryURLPrefix, false)) { |
59 return true; | 47 return true; |
60 } else { | 48 } else { |
61 return false; | 49 return false; |
62 } | 50 } |
63 } | 51 } |
64 | 52 |
65 // This class hosts a SandboxedExtensionUnpacker task and routes the results | |
66 // back to ExtensionsService. The unpack process is started immediately on | |
67 // construction of this object. | |
68 class ExtensionsServiceBackend::UnpackerClient | |
69 : public SandboxedExtensionUnpackerClient { | |
70 public: | |
71 UnpackerClient(ExtensionsServiceBackend* backend, | |
72 const FilePath& extension_path, | |
73 const std::string& expected_id, | |
74 bool silent, bool from_gallery) | |
75 : backend_(backend), extension_path_(extension_path), | |
76 expected_id_(expected_id), silent_(silent), from_gallery_(from_gallery) { | |
77 unpacker_ = new SandboxedExtensionUnpacker(extension_path, | |
78 backend->resource_dispatcher_host_, this); | |
79 unpacker_->Start(); | |
80 } | |
81 | |
82 private: | |
83 // SandboxedExtensionUnpackerClient | |
84 virtual void OnUnpackSuccess(const FilePath& temp_dir, | |
85 const FilePath& extension_dir, | |
86 Extension* extension) { | |
87 backend_->OnExtensionUnpacked(extension_path_, extension_dir, extension, | |
88 expected_id_, silent_, from_gallery_); | |
89 file_util::Delete(temp_dir, true); | |
90 delete this; | |
91 } | |
92 | |
93 virtual void OnUnpackFailure(const std::string& error_message) { | |
94 backend_->ReportExtensionInstallError(extension_path_, error_message); | |
95 delete this; | |
96 } | |
97 | |
98 scoped_refptr<SandboxedExtensionUnpacker> unpacker_; | |
99 | |
100 scoped_refptr<ExtensionsServiceBackend> backend_; | |
101 | |
102 // The path to the crx file that we're installing. | |
103 FilePath extension_path_; | |
104 | |
105 // The path to the copy of the crx file in the temporary directory where we're | |
106 // unpacking it. | |
107 FilePath temp_extension_path_; | |
108 | |
109 // The ID we expect this extension to have, if any. | |
110 std::string expected_id_; | |
111 | |
112 // True if the install should be done with no confirmation dialog. | |
113 bool silent_; | |
114 | |
115 // True if the install is from the gallery (and therefore should not get an | |
116 // alert UI if it turns out to also be a theme). | |
117 bool from_gallery_; | |
118 }; | |
119 | |
120 ExtensionsService::ExtensionsService(Profile* profile, | 53 ExtensionsService::ExtensionsService(Profile* profile, |
121 const CommandLine* command_line, | 54 const CommandLine* command_line, |
122 PrefService* prefs, | 55 PrefService* prefs, |
123 const FilePath& install_directory, | 56 const FilePath& install_directory, |
124 MessageLoop* frontend_loop, | 57 MessageLoop* frontend_loop, |
125 MessageLoop* backend_loop, | 58 MessageLoop* backend_loop, |
126 bool autoupdate_enabled) | 59 bool autoupdate_enabled) |
127 : profile_(profile), | 60 : profile_(profile), |
128 extension_prefs_(new ExtensionPrefs(prefs, install_directory)), | 61 extension_prefs_(new ExtensionPrefs(prefs, install_directory)), |
129 backend_loop_(backend_loop), | 62 backend_loop_(backend_loop), |
(...skipping 10 matching lines...) Expand all Loading... |
140 // Set up the ExtensionUpdater | 73 // Set up the ExtensionUpdater |
141 if (autoupdate_enabled) { | 74 if (autoupdate_enabled) { |
142 int update_frequency = kDefaultUpdateFrequencySeconds; | 75 int update_frequency = kDefaultUpdateFrequencySeconds; |
143 if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) { | 76 if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) { |
144 update_frequency = StringToInt(WideToASCII(command_line->GetSwitchValue( | 77 update_frequency = StringToInt(WideToASCII(command_line->GetSwitchValue( |
145 switches::kExtensionsUpdateFrequency))); | 78 switches::kExtensionsUpdateFrequency))); |
146 } | 79 } |
147 updater_ = new ExtensionUpdater(this, update_frequency, backend_loop_); | 80 updater_ = new ExtensionUpdater(this, update_frequency, backend_loop_); |
148 } | 81 } |
149 | 82 |
150 backend_ = new ExtensionsServiceBackend( | 83 backend_ = new ExtensionsServiceBackend(install_directory_, frontend_loop); |
151 install_directory_, g_browser_process->resource_dispatcher_host(), | |
152 frontend_loop, extensions_enabled()); | |
153 } | 84 } |
154 | 85 |
155 ExtensionsService::~ExtensionsService() { | 86 ExtensionsService::~ExtensionsService() { |
156 UnloadAllExtensions(); | 87 UnloadAllExtensions(); |
157 if (updater_.get()) { | 88 if (updater_.get()) { |
158 updater_->Stop(); | 89 updater_->Stop(); |
159 } | 90 } |
160 } | 91 } |
161 | 92 |
162 void ExtensionsService::SetExtensionsEnabled(bool enabled) { | |
163 extensions_enabled_ = true; | |
164 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), | |
165 &ExtensionsServiceBackend::set_extensions_enabled, enabled)); | |
166 } | |
167 | |
168 void ExtensionsService::Init() { | 93 void ExtensionsService::Init() { |
169 DCHECK(!ready_); | 94 DCHECK(!ready_); |
170 DCHECK_EQ(extensions_.size(), 0u); | 95 DCHECK_EQ(extensions_.size(), 0u); |
171 | 96 |
172 // Start up the extension event routers. | 97 // Start up the extension event routers. |
173 ExtensionBrowserEventRouter::GetInstance()->Init(); | 98 ExtensionBrowserEventRouter::GetInstance()->Init(); |
174 | 99 |
175 LoadAllExtensions(); | 100 LoadAllExtensions(); |
176 | 101 |
177 // TODO(erikkay) this should probably be deferred to a future point | 102 // TODO(erikkay) this should probably be deferred to a future point |
178 // rather than running immediately at startup. | 103 // rather than running immediately at startup. |
179 CheckForExternalUpdates(); | 104 CheckForExternalUpdates(); |
180 | 105 |
181 // TODO(erikkay) this should probably be deferred as well. | 106 // TODO(erikkay) this should probably be deferred as well. |
182 GarbageCollectExtensions(); | 107 GarbageCollectExtensions(); |
183 } | 108 } |
184 | 109 |
185 void ExtensionsService::InstallExtension(const FilePath& extension_path) { | 110 void ExtensionsService::InstallExtension(const FilePath& extension_path) { |
186 InstallExtension(extension_path, GURL(), GURL()); | 111 InstallExtension(extension_path, GURL(), GURL()); |
187 } | 112 } |
188 | 113 |
189 void ExtensionsService::InstallExtension(const FilePath& extension_path, | 114 void ExtensionsService::InstallExtension(const FilePath& extension_path, |
190 const GURL& download_url, | 115 const GURL& download_url, |
191 const GURL& referrer_url) { | 116 const GURL& referrer_url) { |
192 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), | 117 new CrxInstaller(extension_path, install_directory_, Extension::INTERNAL, |
193 &ExtensionsServiceBackend::InstallExtension, extension_path, | 118 "", // no expected id |
194 IsDownloadFromGallery(download_url, referrer_url), | 119 extensions_enabled_, |
195 scoped_refptr<ExtensionsService>(this))); | 120 IsDownloadFromGallery(download_url, referrer_url), |
196 | 121 show_extensions_prompts(), |
| 122 false, // don't delete crx when complete |
| 123 backend_loop_, |
| 124 this); |
197 } | 125 } |
198 | 126 |
199 void ExtensionsService::UpdateExtension(const std::string& id, | 127 void ExtensionsService::UpdateExtension(const std::string& id, |
200 const FilePath& extension_path, | 128 const FilePath& extension_path) { |
201 bool alert_on_error, | 129 |
202 ExtensionInstallCallback* callback) { | 130 if (!GetExtensionById(id)) {» |
203 if (callback) { | 131 LOG(WARNING) << "Will not update extension " << id << " because it is not " |
204 if (install_callbacks_.find(extension_path) != install_callbacks_.end()) { | 132 << "installed";» |
205 // We can't have multiple outstanding install requests for the same | 133 return;» |
206 // path, so immediately indicate error via the callback here. | |
207 LOG(WARNING) << "Dropping update request for '" << | |
208 extension_path.value() << "' (already in progress)'"; | |
209 callback->Run(extension_path, static_cast<Extension*>(NULL)); | |
210 delete callback; | |
211 return; | |
212 } | |
213 install_callbacks_[extension_path] = | |
214 linked_ptr<ExtensionInstallCallback>(callback); | |
215 } | 134 } |
216 | 135 |
217 if (!GetExtensionById(id)) { | 136 new CrxInstaller(extension_path, install_directory_, Extension::INTERNAL, |
218 LOG(WARNING) << "Will not update extension " << id << " because it is not " | 137 id, extensions_enabled_, |
219 << "installed"; | 138 false, // not from gallery |
220 FireInstallCallback(extension_path, NULL); | 139 show_extensions_prompts(), |
221 return; | 140 true, // delete crx when complete |
222 } | 141 backend_loop_, |
223 | 142 this); |
224 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), | |
225 &ExtensionsServiceBackend::UpdateExtension, id, extension_path, | |
226 alert_on_error, scoped_refptr<ExtensionsService>(this))); | |
227 } | 143 } |
228 | 144 |
229 void ExtensionsService::UninstallExtension(const std::string& extension_id, | 145 void ExtensionsService::UninstallExtension(const std::string& extension_id, |
230 bool external_uninstall) { | 146 bool external_uninstall) { |
231 Extension* extension = GetExtensionById(extension_id); | 147 Extension* extension = GetExtensionById(extension_id); |
232 | 148 |
233 // Callers should not send us nonexistant extensions. | 149 // Callers should not send us nonexistant extensions. |
234 DCHECK(extension); | 150 DCHECK(extension); |
235 | 151 |
236 extension_prefs_->OnExtensionUninstalled(extension, external_uninstall); | 152 extension_prefs_->OnExtensionUninstalled(extension, external_uninstall); |
(...skipping 17 matching lines...) Expand all Loading... |
254 void ExtensionsService::LoadAllExtensions() { | 170 void ExtensionsService::LoadAllExtensions() { |
255 // Load the previously installed extensions. | 171 // Load the previously installed extensions. |
256 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), | 172 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), |
257 &ExtensionsServiceBackend::LoadInstalledExtensions, | 173 &ExtensionsServiceBackend::LoadInstalledExtensions, |
258 scoped_refptr<ExtensionsService>(this), | 174 scoped_refptr<ExtensionsService>(this), |
259 new InstalledExtensions(extension_prefs_.get()))); | 175 new InstalledExtensions(extension_prefs_.get()))); |
260 } | 176 } |
261 | 177 |
262 void ExtensionsService::CheckForExternalUpdates() { | 178 void ExtensionsService::CheckForExternalUpdates() { |
263 // This installs or updates externally provided extensions. | 179 // This installs or updates externally provided extensions. |
| 180 // TODO(aa): Why pass this list into the provider, why not just filter it |
| 181 // later? |
264 std::set<std::string> killed_extensions; | 182 std::set<std::string> killed_extensions; |
265 extension_prefs_->GetKilledExtensionIds(&killed_extensions); | 183 extension_prefs_->GetKilledExtensionIds(&killed_extensions); |
266 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), | 184 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), |
267 &ExtensionsServiceBackend::CheckForExternalUpdates, | 185 &ExtensionsServiceBackend::CheckForExternalUpdates, |
268 killed_extensions, | 186 killed_extensions, |
269 scoped_refptr<ExtensionsService>(this))); | 187 scoped_refptr<ExtensionsService>(this))); |
270 } | 188 } |
271 | 189 |
272 void ExtensionsService::UnloadExtension(const std::string& extension_id) { | 190 void ExtensionsService::UnloadExtension(const std::string& extension_id) { |
273 Extension* extension = NULL; | 191 Extension* extension = NULL; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 if ((*iter)->IsTheme() && (*iter)->location() == Extension::LOAD) { | 291 if ((*iter)->IsTheme() && (*iter)->location() == Extension::LOAD) { |
374 NotificationService::current()->Notify( | 292 NotificationService::current()->Notify( |
375 NotificationType::THEME_INSTALLED, | 293 NotificationType::THEME_INSTALLED, |
376 Source<ExtensionsService>(this), | 294 Source<ExtensionsService>(this), |
377 Details<Extension>(*iter)); | 295 Details<Extension>(*iter)); |
378 } | 296 } |
379 } | 297 } |
380 } | 298 } |
381 } | 299 } |
382 | 300 |
383 void ExtensionsService::OnExtensionInstalled(const FilePath& path, | 301 void ExtensionsService::OnExtensionInstalled(Extension* extension) { |
384 Extension* extension, Extension::InstallType install_type) { | |
385 FireInstallCallback(path, extension); | |
386 extension_prefs_->OnExtensionInstalled(extension); | 302 extension_prefs_->OnExtensionInstalled(extension); |
387 | 303 |
388 // If the extension is a theme, tell the profile (and therefore ThemeProvider) | 304 // If the extension is a theme, tell the profile (and therefore ThemeProvider) |
389 // to apply it. | 305 // to apply it. |
390 if (extension->IsTheme()) { | 306 if (extension->IsTheme()) { |
391 ShowThemePreviewInfobar(extension); | 307 ShowThemePreviewInfobar(extension); |
392 NotificationService::current()->Notify( | 308 NotificationService::current()->Notify( |
393 NotificationType::THEME_INSTALLED, | 309 NotificationType::THEME_INSTALLED, |
394 Source<ExtensionsService>(this), | 310 Source<ExtensionsService>(this), |
395 Details<Extension>(extension)); | 311 Details<Extension>(extension)); |
396 } else { | 312 } else { |
397 NotificationService::current()->Notify( | 313 NotificationService::current()->Notify( |
398 NotificationType::EXTENSION_INSTALLED, | 314 NotificationType::EXTENSION_INSTALLED, |
399 Source<ExtensionsService>(this), | 315 Source<ExtensionsService>(this), |
400 Details<Extension>(extension)); | 316 Details<Extension>(extension)); |
401 } | 317 } |
| 318 |
| 319 // Also load the extension. |
| 320 ExtensionList* list = new ExtensionList; |
| 321 list->push_back(extension); |
| 322 OnExtensionsLoaded(list); |
402 } | 323 } |
403 | 324 |
404 | 325 |
405 void ExtensionsService::OnExtenionInstallError(const FilePath& path) { | 326 void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) { |
406 FireInstallCallback(path, NULL); | |
407 } | |
408 | |
409 void ExtensionsService::FireInstallCallback(const FilePath& path, | |
410 Extension* extension) { | |
411 CallbackMap::iterator iter = install_callbacks_.find(path); | |
412 if (iter != install_callbacks_.end()) { | |
413 iter->second->Run(path, extension); | |
414 install_callbacks_.erase(iter); | |
415 } | |
416 } | |
417 | |
418 void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id, | |
419 const FilePath& path) { | |
420 FireInstallCallback(path, NULL); | |
421 Extension* extension = GetExtensionById(id); | 327 Extension* extension = GetExtensionById(id); |
422 if (extension && extension->IsTheme()) { | 328 if (extension && extension->IsTheme()) { |
423 ShowThemePreviewInfobar(extension); | 329 ShowThemePreviewInfobar(extension); |
424 NotificationService::current()->Notify( | 330 NotificationService::current()->Notify( |
425 NotificationType::THEME_INSTALLED, | 331 NotificationType::THEME_INSTALLED, |
426 Source<ExtensionsService>(this), | 332 Source<ExtensionsService>(this), |
427 Details<Extension>(extension)); | 333 Details<Extension>(extension)); |
428 } | 334 } |
429 } | 335 } |
430 | 336 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 | 371 |
466 TabContents* tab_contents = browser->GetSelectedTabContents(); | 372 TabContents* tab_contents = browser->GetSelectedTabContents(); |
467 if (!tab_contents) | 373 if (!tab_contents) |
468 return false; | 374 return false; |
469 | 375 |
470 tab_contents->AddInfoBar(new ThemePreviewInfobarDelegate(tab_contents, | 376 tab_contents->AddInfoBar(new ThemePreviewInfobarDelegate(tab_contents, |
471 extension->name())); | 377 extension->name())); |
472 return true; | 378 return true; |
473 } | 379 } |
474 | 380 |
| 381 void ExtensionsService::OnExternalExtensionFound(const std::string& id, |
| 382 const std::string& version, |
| 383 const FilePath& path, |
| 384 Extension::Location location) { |
| 385 // Before even bothering to unpack, check and see if we already have this |
| 386 // version. This is important because these extensions are going to get |
| 387 // installed on every startup. |
| 388 Extension* existing = GetExtensionById(id); |
| 389 if (existing) { |
| 390 switch (existing->version()->CompareTo( |
| 391 *Version::GetVersionFromString(version))) { |
| 392 case -1: // existing version is older, we should upgrade |
| 393 break; |
| 394 case 0: // existing version is same, do nothing |
| 395 return; |
| 396 case 1: // existing version is newer, uh-oh |
| 397 LOG(WARNING) << "Found external version of extension " << id |
| 398 << "that is older than current version. Current version " |
| 399 << "is: " << existing->VersionString() << ". New version " |
| 400 << "is: " << version << ". Keeping current version."; |
| 401 return; |
| 402 } |
| 403 } |
| 404 |
| 405 new CrxInstaller(path, install_directory_, location, id, extensions_enabled_, |
| 406 false, // not from gallery |
| 407 show_extensions_prompts(), |
| 408 false, // don't delete crx when complete |
| 409 backend_loop_, |
| 410 this); |
| 411 } |
| 412 |
| 413 |
475 // ExtensionsServicesBackend | 414 // ExtensionsServicesBackend |
476 | 415 |
477 ExtensionsServiceBackend::ExtensionsServiceBackend( | 416 ExtensionsServiceBackend::ExtensionsServiceBackend( |
478 const FilePath& install_directory, ResourceDispatcherHost* rdh, | 417 const FilePath& install_directory, MessageLoop* frontend_loop) |
479 MessageLoop* frontend_loop, bool extensions_enabled) | |
480 : frontend_(NULL), | 418 : frontend_(NULL), |
481 install_directory_(install_directory), | 419 install_directory_(install_directory), |
482 resource_dispatcher_host_(rdh), | |
483 alert_on_error_(false), | 420 alert_on_error_(false), |
484 frontend_loop_(frontend_loop), | 421 frontend_loop_(frontend_loop) { |
485 extensions_enabled_(extensions_enabled) { | 422 // TODO(aa): This ends up doing blocking IO on the UI thread because it reads |
| 423 // pref data in the ctor and that is called on the UI thread. Would be better |
| 424 // to re-read data each time we list external extensions, anyway. |
486 external_extension_providers_[Extension::EXTERNAL_PREF] = | 425 external_extension_providers_[Extension::EXTERNAL_PREF] = |
487 linked_ptr<ExternalExtensionProvider>( | 426 linked_ptr<ExternalExtensionProvider>( |
488 new ExternalPrefExtensionProvider()); | 427 new ExternalPrefExtensionProvider()); |
489 #if defined(OS_WIN) | 428 #if defined(OS_WIN) |
490 external_extension_providers_[Extension::EXTERNAL_REGISTRY] = | 429 external_extension_providers_[Extension::EXTERNAL_REGISTRY] = |
491 linked_ptr<ExternalExtensionProvider>( | 430 linked_ptr<ExternalExtensionProvider>( |
492 new ExternalRegistryExtensionProvider()); | 431 new ExternalRegistryExtensionProvider()); |
493 #endif | 432 #endif |
494 } | 433 } |
495 | 434 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 path_str.c_str(), error.c_str()); | 521 path_str.c_str(), error.c_str()); |
583 ExtensionErrorReporter::GetInstance()->ReportError(message, alert_on_error_); | 522 ExtensionErrorReporter::GetInstance()->ReportError(message, alert_on_error_); |
584 } | 523 } |
585 | 524 |
586 void ExtensionsServiceBackend::ReportExtensionsLoaded( | 525 void ExtensionsServiceBackend::ReportExtensionsLoaded( |
587 ExtensionList* extensions) { | 526 ExtensionList* extensions) { |
588 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 527 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
589 frontend_, &ExtensionsService::OnExtensionsLoaded, extensions)); | 528 frontend_, &ExtensionsService::OnExtensionsLoaded, extensions)); |
590 } | 529 } |
591 | 530 |
592 void ExtensionsServiceBackend::InstallExtension( | |
593 const FilePath& extension_path, bool from_gallery, | |
594 scoped_refptr<ExtensionsService> frontend) { | |
595 LOG(INFO) << "Installing extension " << extension_path.value(); | |
596 | |
597 frontend_ = frontend; | |
598 alert_on_error_ = true; | |
599 | |
600 InstallOrUpdateExtension(extension_path, from_gallery, std::string(), false); | |
601 } | |
602 | |
603 void ExtensionsServiceBackend::UpdateExtension(const std::string& id, | |
604 const FilePath& extension_path, bool alert_on_error, | |
605 scoped_refptr<ExtensionsService> frontend) { | |
606 LOG(INFO) << "Updating extension " << id << " " << extension_path.value(); | |
607 | |
608 frontend_ = frontend; | |
609 alert_on_error_ = alert_on_error; | |
610 | |
611 InstallOrUpdateExtension(extension_path, false, id, true); | |
612 } | |
613 | |
614 void ExtensionsServiceBackend::InstallOrUpdateExtension( | |
615 const FilePath& extension_path, bool from_gallery, | |
616 const std::string& expected_id, bool silent) { | |
617 UnpackerClient* client = new UnpackerClient( | |
618 this, extension_path, expected_id, silent, from_gallery); | |
619 } | |
620 | |
621 void ExtensionsServiceBackend::OnExtensionUnpacked( | |
622 const FilePath& crx_path, const FilePath& unpacked_path, | |
623 Extension* extension, const std::string expected_id, bool silent, | |
624 bool from_gallery) { | |
625 // Take ownership of the extension object. | |
626 scoped_ptr<Extension> extension_deleter(extension); | |
627 | |
628 Extension::Location location = Extension::INTERNAL; | |
629 LookupExternalExtension(extension->id(), NULL, &location); | |
630 extension->set_location(location); | |
631 | |
632 bool allow_install = false; | |
633 if (extensions_enabled_) | |
634 allow_install = true; | |
635 | |
636 // Always allow themes. | |
637 if (extension->IsTheme()) | |
638 allow_install = true; | |
639 | |
640 // Always allow externally installed extensions (partners use this). | |
641 if (Extension::IsExternalLocation(location)) | |
642 allow_install = true; | |
643 | |
644 if (!allow_install) { | |
645 ReportExtensionInstallError(crx_path, "Extensions are not enabled."); | |
646 return; | |
647 } | |
648 | |
649 // TODO(extensions): Make better extensions UI. http://crbug.com/12116 | |
650 | |
651 // We also skip the dialog for a few special cases: | |
652 // - themes (because we show the preview infobar for them) | |
653 // - externally registered extensions | |
654 // - during tests (!frontend->show_extension_prompts()) | |
655 // - autoupdate (silent). | |
656 bool show_dialog = true; | |
657 if (extension->IsTheme()) | |
658 show_dialog = false; | |
659 | |
660 if (Extension::IsExternalLocation(location)) | |
661 show_dialog = false; | |
662 | |
663 if (silent || !frontend_->show_extensions_prompts()) | |
664 show_dialog = false; | |
665 | |
666 if (show_dialog) { | |
667 #if defined(OS_WIN) | |
668 if (win_util::MessageBox(GetForegroundWindow(), | |
669 L"Are you sure you want to install this extension?\n\n" | |
670 L"You should only install extensions from sources you trust.", | |
671 l10n_util::GetString(IDS_PRODUCT_NAME).c_str(), | |
672 MB_OKCANCEL) != IDOK) { | |
673 return; | |
674 } | |
675 #elif defined(OS_MACOSX) | |
676 // Using CoreFoundation to do this dialog is unimaginably lame but will do | |
677 // until the UI is redone. | |
678 scoped_cftyperef<CFStringRef> product_name( | |
679 base::SysWideToCFStringRef(l10n_util::GetString(IDS_PRODUCT_NAME))); | |
680 CFOptionFlags response; | |
681 CFUserNotificationDisplayAlert( | |
682 0, kCFUserNotificationCautionAlertLevel, NULL, NULL, NULL, | |
683 product_name, | |
684 CFSTR("Are you sure you want to install this extension?\n\n" | |
685 "This is a temporary message and it will be removed when " | |
686 "extensions UI is finalized."), | |
687 NULL, CFSTR("Cancel"), NULL, &response); | |
688 | |
689 if (response == kCFUserNotificationAlternateResponse) { | |
690 ReportExtensionInstallError(extension_path, | |
691 "User did not allow extension to be installed."); | |
692 return; | |
693 } | |
694 #endif // OS_* | |
695 } | |
696 | |
697 // If an expected id was provided, make sure it matches. | |
698 if (!expected_id.empty() && expected_id != extension->id()) { | |
699 ReportExtensionInstallError(crx_path, | |
700 StringPrintf("ID in new extension manifest (%s) does not match " | |
701 "expected id (%s)", extension->id(), expected_id)); | |
702 return; | |
703 } | |
704 | |
705 FilePath version_dir; | |
706 Extension::InstallType install_type = Extension::INSTALL_ERROR; | |
707 std::string error_msg; | |
708 if (!extension_file_util::InstallExtension(unpacked_path, install_directory_, | |
709 extension->id(), | |
710 extension->VersionString(), | |
711 &version_dir, | |
712 &install_type, &error_msg)) { | |
713 ReportExtensionInstallError(crx_path, error_msg); | |
714 return; | |
715 } | |
716 | |
717 if (install_type == Extension::DOWNGRADE) { | |
718 ReportExtensionInstallError(crx_path, "Attempted to downgrade extension."); | |
719 return; | |
720 } | |
721 | |
722 extension->set_path(version_dir); | |
723 | |
724 if (install_type == Extension::REINSTALL) { | |
725 // The client may use this as a signal (to switch themes, for instance). | |
726 ReportExtensionOverinstallAttempted(extension->id(), crx_path); | |
727 return; | |
728 } | |
729 | |
730 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( | |
731 frontend_, &ExtensionsService::OnExtensionInstalled, crx_path, | |
732 extension, install_type)); | |
733 | |
734 // Only one extension, but ReportExtensionsLoaded can handle multiple, | |
735 // so we need to construct a list. | |
736 ExtensionList* extensions = new ExtensionList; | |
737 | |
738 // Hand off ownership of the extension to the frontend. | |
739 extensions->push_back(extension_deleter.release()); | |
740 ReportExtensionsLoaded(extensions); | |
741 } | |
742 | |
743 void ExtensionsServiceBackend::ReportExtensionInstallError( | |
744 const FilePath& extension_path, const std::string &error) { | |
745 | |
746 // TODO(erikkay): note that this isn't guaranteed to work properly on Linux. | |
747 std::string path_str = WideToASCII(extension_path.ToWStringHack()); | |
748 std::string message = | |
749 StringPrintf("Could not install extension from '%s'. %s", | |
750 path_str.c_str(), error.c_str()); | |
751 ExtensionErrorReporter::GetInstance()->ReportError(message, alert_on_error_); | |
752 | |
753 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( | |
754 frontend_, | |
755 &ExtensionsService::OnExtenionInstallError, | |
756 extension_path)); | |
757 } | |
758 | |
759 void ExtensionsServiceBackend::ReportExtensionOverinstallAttempted( | |
760 const std::string& id, const FilePath& path) { | |
761 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( | |
762 frontend_, &ExtensionsService::OnExtensionOverinstallAttempted, id, | |
763 path)); | |
764 } | |
765 | |
766 bool ExtensionsServiceBackend::LookupExternalExtension( | 531 bool ExtensionsServiceBackend::LookupExternalExtension( |
767 const std::string& id, Version** version, Extension::Location* location) { | 532 const std::string& id, Version** version, Extension::Location* location) { |
768 scoped_ptr<Version> extension_version; | 533 scoped_ptr<Version> extension_version; |
769 for (ProviderMap::const_iterator i = external_extension_providers_.begin(); | 534 for (ProviderMap::const_iterator i = external_extension_providers_.begin(); |
770 i != external_extension_providers_.end(); ++i) { | 535 i != external_extension_providers_.end(); ++i) { |
771 const ExternalExtensionProvider* provider = i->second.get(); | 536 const ExternalExtensionProvider* provider = i->second.get(); |
772 extension_version.reset(provider->RegisteredVersion(id, location)); | 537 extension_version.reset(provider->RegisteredVersion(id, location)); |
773 if (extension_version.get()) { | 538 if (extension_version.get()) { |
774 if (version) | 539 if (version) |
775 *version = extension_version.release(); | 540 *version = extension_version.release(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
828 | 593 |
829 void ExtensionsServiceBackend::SetProviderForTesting( | 594 void ExtensionsServiceBackend::SetProviderForTesting( |
830 Extension::Location location, | 595 Extension::Location location, |
831 ExternalExtensionProvider* test_provider) { | 596 ExternalExtensionProvider* test_provider) { |
832 DCHECK(test_provider); | 597 DCHECK(test_provider); |
833 external_extension_providers_[location] = | 598 external_extension_providers_[location] = |
834 linked_ptr<ExternalExtensionProvider>(test_provider); | 599 linked_ptr<ExternalExtensionProvider>(test_provider); |
835 } | 600 } |
836 | 601 |
837 void ExtensionsServiceBackend::OnExternalExtensionFound( | 602 void ExtensionsServiceBackend::OnExternalExtensionFound( |
838 const std::string& id, const Version* version, const FilePath& path) { | 603 const std::string& id, const Version* version, const FilePath& path, |
839 InstallOrUpdateExtension(path, | 604 Extension::Location location) { |
840 false, // not from gallery | 605 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(frontend_, |
841 id, // expected id | 606 &ExtensionsService::OnExternalExtensionFound, id, version->GetString(), |
842 true); // silent | 607 path, location)); |
843 } | 608 } |
OLD | NEW |