Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(309)

Side by Side Diff: chrome/browser/extensions/extensions_service.cc

Issue 160311: Pull CrxInstaller out of ExtensionsService. (Closed)
Patch Set: Fix leak of SandboxedExtensionUnpacker Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extensions_service.h ('k') | chrome/browser/extensions/extensions_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698