| 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 |