1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/extension_service.h" 6 7 #include <algorithm> 8 #include <set> 9 10 #include "base/basictypes.h" 11 #include "base/command_line.h" 12 #include "base/file_util.h" 13 #include "base/metrics/histogram.h" 14 #include "base/path_service.h" 15 #include "base/stl_util-inl.h" 16 #include "base/string16.h" 17 #include "base/string_number_conversions.h" 18 #include "base/string_util.h" 19 #include "base/stringprintf.h" 20 #include "base/threading/thread_restrictions.h" 21 #include "base/time.h" 22 #include "base/utf_string_conversions.h" 23 #include "base/values.h" 24 #include "base/version.h" 25 #include "chrome/browser/browser_process.h" 26 #include "chrome/browser/debugger/devtools_manager.h" 27 #include "chrome/browser/extensions/crx_installer.h" 28 #include "chrome/browser/extensions/apps_promo.h" 29 #include "chrome/browser/extensions/extension_accessibility_api.h" 30 #include "chrome/browser/extensions/extension_bookmarks_module.h" 31 #include "chrome/browser/extensions/extension_browser_event_router.h" 32 #include "chrome/browser/extensions/extension_cookies_api.h" 33 #include "chrome/browser/extensions/extension_data_deleter.h" 34 #include "chrome/browser/extensions/extension_error_reporter.h" 35 #include "chrome/browser/extensions/extension_history_api.h" 36 #include "chrome/browser/extensions/extension_host.h" 37 #include "chrome/browser/extensions/extension_management_api.h" 38 #include "chrome/browser/extensions/extension_preference_api.h" 39 #include "chrome/browser/extensions/extension_process_manager.h" 40 #include "chrome/browser/extensions/extension_processes_api.h" 41 #include "chrome/browser/extensions/extension_special_storage_policy.h" 42 #include "chrome/browser/extensions/extension_sync_data.h" 43 #include "chrome/browser/extensions/extension_updater.h" 44 #include "chrome/browser/extensions/extension_web_ui.h" 45 #include "chrome/browser/extensions/extension_webnavigation_api.h" 46 #include "chrome/browser/extensions/external_extension_provider_impl.h" 47 #include "chrome/browser/extensions/external_extension_provider_interface.h" 48 #include "chrome/browser/extensions/pending_extension_manager.h" 49 #include "chrome/browser/net/chrome_url_request_context.h" 50 #include "chrome/browser/prefs/pref_service.h" 51 #include "chrome/browser/profiles/profile.h" 52 #include "chrome/browser/search_engines/template_url_model.h" 53 #include "chrome/browser/themes/theme_service.h" 54 #include "chrome/browser/themes/theme_service_factory.h" 55 #include "chrome/browser/ui/webui/shown_sections_handler.h" 56 #include "chrome/common/child_process_logging.h" 57 #include "chrome/common/chrome_paths.h" 58 #include "chrome/common/chrome_switches.h" 59 #include "chrome/common/extensions/extension.h" 60 #include "chrome/common/extensions/extension_constants.h" 61 #include "chrome/common/extensions/extension_error_utils.h" 62 #include "chrome/common/extensions/extension_file_util.h" 63 #include "chrome/common/extensions/extension_l10n_util.h" 64 #include "chrome/common/extensions/extension_resource.h" 65 #include "chrome/common/pref_names.h" 66 #include "chrome/common/url_constants.h" 67 #include "content/browser/browser_thread.h" 68 #include "content/browser/plugin_process_host.h" 69 #include "content/browser/plugin_service.h" 70 #include "content/common/json_value_serializer.h" 71 #include "content/common/notification_service.h" 72 #include "content/common/notification_type.h" 73 #include "content/common/pepper_plugin_registry.h" 74 #include "googleurl/src/gurl.h" 75 #include "net/base/registry_controlled_domain.h" 76 #include "webkit/database/database_tracker.h" 77 #include "webkit/database/database_util.h" 78 #include "webkit/plugins/npapi/plugin_list.h" 79 80 #if defined(OS_CHROMEOS) 81 #include "chrome/browser/chromeos/extensions/file_browser_event_router.h" 82 #include "webkit/fileapi/file_system_context.h" 83 #include "webkit/fileapi/file_system_mount_point_provider.h" 84 #include "webkit/fileapi/file_system_path_manager.h" 85 #endif 86 87 using base::Time; 88 89 namespace errors = extension_manifest_errors; 90 91 namespace { 92 93 #if defined(OS_LINUX) 94 static const int kOmniboxIconPaddingLeft = 2; 95 static const int kOmniboxIconPaddingRight = 2; 96 #elif defined(OS_MACOSX) 97 static const int kOmniboxIconPaddingLeft = 0; 98 static const int kOmniboxIconPaddingRight = 2; 99 #else 100 static const int kOmniboxIconPaddingLeft = 0; 101 static const int kOmniboxIconPaddingRight = 0; 102 #endif 103 104 // The following enumeration is used in histograms matching 105 // Extensions.ManifestReload* . Values may be added, as long 106 // as existing values are not changed. 107 enum ManifestReloadReason { 108 NOT_NEEDED = 0, // Reload not needed. 109 UNPACKED_DIR, // Unpacked directory 110 NEEDS_RELOCALIZATION, // The local has changed since we read this extension. 111 NUM_MANIFEST_RELOAD_REASONS 112 }; 113 114 ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) { 115 // Always reload manifests of unpacked extensions, because they can change 116 // on disk independent of the manifest in our prefs. 117 if (info.extension_location == Extension::LOAD) 118 return UNPACKED_DIR; 119 120 // Reload the manifest if it needs to be relocalized. 121 if (extension_l10n_util::ShouldRelocalizeManifest(info)) 122 return NEEDS_RELOCALIZATION; 123 124 return NOT_NEEDED; 125 } 126 127 static void ForceShutdownPlugin(const FilePath& plugin_path) { 128 PluginProcessHost* plugin = 129 PluginService::GetInstance()->FindNpapiPluginProcess(plugin_path); 130 if (plugin) 131 plugin->ForceShutdown(); 132 } 133 134 } // namespace 135 136 ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData() 137 : background_page_ready(false), 138 being_upgraded(false) { 139 } 140 141 ExtensionService::ExtensionRuntimeData::~ExtensionRuntimeData() { 142 } 143 144 ExtensionService::NaClModuleInfo::NaClModuleInfo() { 145 } 146 147 ExtensionService::NaClModuleInfo::~NaClModuleInfo() { 148 } 149 150 // ExtensionService. 151 152 const char* ExtensionService::kInstallDirectoryName = "Extensions"; 153 const char* ExtensionService::kCurrentVersionFileName = "Current Version"; 154 155 // Implements IO for the ExtensionService. 156 157 class ExtensionServiceBackend 158 : public base::RefCountedThreadSafe<ExtensionServiceBackend> { 159 public: 160 // |install_directory| is a path where to look for extensions to load. 161 explicit ExtensionServiceBackend(const FilePath& install_directory); 162 163 // Loads a single extension from |path| where |path| is the top directory of 164 // a specific extension where its manifest file lives. 165 // Errors are reported through ExtensionErrorReporter. On success, 166 // AddExtension() is called. 167 // TODO(erikkay): It might be useful to be able to load a packed extension 168 // (presumably into memory) without installing it. 169 void LoadSingleExtension(const FilePath &path, 170 scoped_refptr<ExtensionService> frontend); 171 172 private: 173 friend class base::RefCountedThreadSafe<ExtensionServiceBackend>; 174 175 virtual ~ExtensionServiceBackend(); 176 177 // Finish installing the extension in |crx_path| after it has been unpacked to 178 // |unpacked_path|. If |expected_id| is not empty, it's verified against the 179 // extension's manifest before installation. If |silent| is true, there will 180 // be no install confirmation dialog. |from_gallery| indicates whether the 181 // crx was installed from our gallery, which results in different UI. 182 // 183 // Note: We take ownership of |extension|. 184 void OnExtensionUnpacked(const FilePath& crx_path, 185 const FilePath& unpacked_path, 186 const Extension* extension, 187 const std::string expected_id); 188 189 // Notify the frontend that there was an error loading an extension. 190 void ReportExtensionLoadError(const FilePath& extension_path, 191 const std::string& error); 192 193 // This is a naked pointer which is set by each entry point. 194 // The entry point is responsible for ensuring lifetime. 195 ExtensionService* frontend_; 196 197 // The top-level extensions directory being installed to. 198 FilePath install_directory_; 199 200 // Whether errors result in noisy alerts. 201 bool alert_on_error_; 202 203 DISALLOW_COPY_AND_ASSIGN(ExtensionServiceBackend); 204 }; 205 206 ExtensionServiceBackend::ExtensionServiceBackend( 207 const FilePath& install_directory) 208 : frontend_(NULL), 209 install_directory_(install_directory), 210 alert_on_error_(false) { 211 } 212 213 ExtensionServiceBackend::~ExtensionServiceBackend() { 214 } 215 216 void ExtensionServiceBackend::LoadSingleExtension( 217 const FilePath& path_in, scoped_refptr<ExtensionService> frontend) { 218 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 219 220 frontend_ = frontend; 221 222 // Explicit UI loads are always noisy. 223 alert_on_error_ = true; 224 225 FilePath extension_path = path_in; 226 file_util::AbsolutePath(&extension_path); 227 228 int flags = Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD) ? 229 Extension::ALLOW_FILE_ACCESS : Extension::NO_FLAGS; 230 if (Extension::ShouldDoStrictErrorChecking(Extension::LOAD)) 231 flags |= Extension::STRICT_ERROR_CHECKS; 232 std::string error; 233 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension( 234 extension_path, 235 Extension::LOAD, 236 flags, 237 &error)); 238 239 if (!extension) { 240 ReportExtensionLoadError(extension_path, error); 241 return; 242 } 243 244 // Report this as an installed extension so that it gets remembered in the 245 // prefs. 246 BrowserThread::PostTask( 247 BrowserThread::UI, FROM_HERE, 248 NewRunnableMethod(frontend_, 249 &ExtensionService::OnExtensionInstalled, 250 extension)); 251 } 252 253 void ExtensionServiceBackend::ReportExtensionLoadError( 254 const FilePath& extension_path, const std::string &error) { 255 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 256 BrowserThread::PostTask( 257 BrowserThread::UI, FROM_HERE, 258 NewRunnableMethod( 259 frontend_, 260 &ExtensionService::ReportExtensionLoadError, extension_path, 261 error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_)); 262 } 263 264 void ExtensionService::CheckExternalUninstall(const std::string& id) { 265 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 266 267 // Check if the providers know about this extension. 268 ProviderCollection::const_iterator i; 269 for (i = external_extension_providers_.begin(); 270 i != external_extension_providers_.end(); ++i) { 271 DCHECK(i->get()->IsReady()); 272 if (i->get()->HasExtension(id)) 273 return; // Yup, known extension, don't uninstall. 274 } 275 276 // This is an external extension that we don't have registered. Uninstall. 277 UninstallExtension(id, true, NULL); 278 } 279 280 void ExtensionService::ClearProvidersForTesting() { 281 external_extension_providers_.clear(); 282 } 283 284 void ExtensionService::AddProviderForTesting( 285 ExternalExtensionProviderInterface* test_provider) { 286 CHECK(test_provider); 287 external_extension_providers_.push_back( 288 linked_ptr<ExternalExtensionProviderInterface>(test_provider)); 289 } 290 291 void ExtensionService::OnExternalExtensionUpdateUrlFound( 292 const std::string& id, 293 const GURL& update_url, 294 Extension::Location location) { 295 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 296 CHECK(Extension::IdIsValid(id)); 297 298 if (GetExtensionById(id, true)) { 299 // Already installed. Do not change the update URL that the extension set. 300 return; 301 } 302 pending_extension_manager()->AddFromExternalUpdateUrl( 303 id, update_url, location); 304 external_extension_url_added_ |= true; 305 } 306 307 bool ExtensionService::IsDownloadFromGallery(const GURL& download_url, 308 const GURL& referrer_url) { 309 // Special-case the themes mini-gallery. 310 // TODO(erikkay) When that gallery goes away, remove this code. 311 if (IsDownloadFromMiniGallery(download_url) && 312 StartsWithASCII(referrer_url.spec(), 313 extension_urls::kMiniGalleryBrowsePrefix, false)) { 314 return true; 315 } 316 317 const Extension* download_extension = GetExtensionByWebExtent(download_url); 318 const Extension* referrer_extension = GetExtensionByWebExtent(referrer_url); 319 const Extension* webstore_app = GetWebStoreApp(); 320 321 bool referrer_valid = (referrer_extension == webstore_app); 322 bool download_valid = (download_extension == webstore_app); 323 324 // If the command-line gallery URL is set, then be a bit more lenient. 325 GURL store_url = 326 GURL(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 327 switches::kAppsGalleryURL)); 328 if (!store_url.is_empty()) { 329 std::string store_tld = 330 net::RegistryControlledDomainService::GetDomainAndRegistry(store_url); 331 if (!referrer_valid) { 332 std::string referrer_tld = 333 net::RegistryControlledDomainService::GetDomainAndRegistry( 334 referrer_url); 335 // The referrer gets stripped when transitioning from https to http, 336 // or when hitting an unknown test cert and that commonly happens in 337 // testing environments. Given this, we allow an empty referrer when 338 // the command-line flag is set. 339 // Otherwise, the TLD must match the TLD of the command-line url. 340 referrer_valid = referrer_url.is_empty() || (referrer_tld == store_tld); 341 } 342 343 if (!download_valid) { 344 std::string download_tld = 345 net::RegistryControlledDomainService::GetDomainAndRegistry( 346 GURL(download_url)); 347 348 // Otherwise, the TLD must match the TLD of the command-line url. 349 download_valid = (download_tld == store_tld); 350 } 351 } 352 353 return (referrer_valid && download_valid); 354 } 355 356 bool ExtensionService::IsDownloadFromMiniGallery(const GURL& download_url) { 357 return StartsWithASCII(download_url.spec(), 358 extension_urls::kMiniGalleryDownloadPrefix, 359 false); // case_sensitive 360 } 361 362 const Extension* ExtensionService::GetInstalledApp(const GURL& url) { 363 // Check for hosted app. 364 const Extension* app = GetExtensionByWebExtent(url); 365 if (app) 366 return app; 367 368 // Check for packaged app. 369 app = GetExtensionByURL(url); 370 if (app && app->is_app()) 371 return app; 372 373 return NULL; 374 } 375 376 bool ExtensionService::IsInstalledApp(const GURL& url) { 377 return !!GetInstalledApp(url); 378 } 379 380 // static 381 // This function is used to implement the command-line switch 382 // --uninstall-extension. The LOG statements within this function are used to 383 // inform the user if the uninstall cannot be done. 384 bool ExtensionService::UninstallExtensionHelper( 385 ExtensionService* extensions_service, 386 const std::string& extension_id) { 387 388 const Extension* extension = 389 extensions_service->GetExtensionById(extension_id, true); 390 if (!extension) 391 extension = extensions_service->GetTerminatedExtension(extension_id); 392 393 // We can't call UninstallExtension with an invalid extension ID. 394 if (!extension) { 395 LOG(WARNING) << "Attempted uninstallation of non-existent extension with " 396 << "id: " << extension_id; 397 return false; 398 } 399 400 // The following call to UninstallExtension will not allow an uninstall of a 401 // policy-controlled extension. 402 std::string error; 403 if (!extensions_service->UninstallExtension(extension_id, false, &error)) { 404 LOG(WARNING) << "Cannot uninstall extension with id " << extension_id 405 << ": " << error; 406 return false; 407 } 408 409 return true; 410 } 411 412 ExtensionService::ExtensionService(Profile* profile, 413 const CommandLine* command_line, 414 const FilePath& install_directory, 415 ExtensionPrefs* extension_prefs, 416 bool autoupdate_enabled, 417 bool extensions_enabled) 418 : profile_(profile), 419 extension_prefs_(extension_prefs), 420 ALLOW_THIS_IN_INITIALIZER_LIST(pending_extension_manager_(*this)), 421 install_directory_(install_directory), 422 extensions_enabled_(extensions_enabled), 423 show_extensions_prompts_(true), 424 ready_(false), 425 ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)), 426 apps_promo_(profile->GetPrefs()), 427 event_routers_initialized_(false) { 428 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 429 430 // Figure out if extension installation should be enabled. 431 if (command_line->HasSwitch(switches::kDisableExtensions)) { 432 extensions_enabled_ = false; 433 } else if (profile->GetPrefs()->GetBoolean(prefs::kDisableExtensions)) { 434 extensions_enabled_ = false; 435 } 436 437 registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED, 438 NotificationService::AllSources()); 439 pref_change_registrar_.Init(profile->GetPrefs()); 440 pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, this); 441 pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, this); 442 443 // Set up the ExtensionUpdater 444 if (autoupdate_enabled) { 445 int update_frequency = kDefaultUpdateFrequencySeconds; 446 if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) { 447 base::StringToInt(command_line->GetSwitchValueASCII( 448 switches::kExtensionsUpdateFrequency), 449 &update_frequency); 450 } 451 updater_.reset(new ExtensionUpdater(this, 452 extension_prefs, 453 profile->GetPrefs(), 454 profile, 455 update_frequency)); 456 } 457 458 backend_ = new ExtensionServiceBackend(install_directory_); 459 460 if (extensions_enabled_) { 461 ExternalExtensionProviderImpl::CreateExternalProviders( 462 this, profile_, &external_extension_providers_); 463 } 464 465 // Use monochrome icons for Omnibox icons. 466 omnibox_popup_icon_manager_.set_monochrome(true); 467 omnibox_icon_manager_.set_monochrome(true); 468 omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft, 469 0, kOmniboxIconPaddingRight)); 470 } 471 472 const ExtensionList* ExtensionService::extensions() const { 473 return &extensions_; 474 } 475 476 const ExtensionList* ExtensionService::disabled_extensions() const { 477 return &disabled_extensions_; 478 } 479 480 const ExtensionList* ExtensionService::terminated_extensions() const { 481 return &terminated_extensions_; 482 } 483 484 PendingExtensionManager* ExtensionService::pending_extension_manager() { 485 return &pending_extension_manager_; 486 } 487 488 ExtensionService::~ExtensionService() { 489 DCHECK(!profile_); // Profile should have told us it's going away. 490 UnloadAllExtensions(); 491 492 ProviderCollection::const_iterator i; 493 for (i = external_extension_providers_.begin(); 494 i != external_extension_providers_.end(); ++i) { 495 ExternalExtensionProviderInterface* provider = i->get(); 496 provider->ServiceShutdown(); 497 } 498 499 #if defined(OS_CHROMEOS) 500 if (event_routers_initialized_) { 501 ExtensionFileBrowserEventRouter::GetInstance()-> 502 StopObservingFileSystemEvents(); 503 } 504 #endif 505 } 506 507 void ExtensionService::InitEventRouters() { 508 if (event_routers_initialized_) 509 return; 510 511 ExtensionHistoryEventRouter::GetInstance()->ObserveProfile(profile_); 512 ExtensionAccessibilityEventRouter::GetInstance()->ObserveProfile(profile_); 513 browser_event_router_.reset(new ExtensionBrowserEventRouter(profile_)); 514 browser_event_router_->Init(); 515 preference_event_router_.reset(new ExtensionPreferenceEventRouter(profile_)); 516 ExtensionBookmarkEventRouter::GetInstance()->Observe( 517 profile_->GetBookmarkModel()); 518 ExtensionCookiesEventRouter::GetInstance()->Init(); 519 ExtensionManagementEventRouter::GetInstance()->Init(); 520 ExtensionProcessesEventRouter::GetInstance()->ObserveProfile(profile_); 521 ExtensionWebNavigationEventRouter::GetInstance()->Init(); 522 #if defined(OS_CHROMEOS) 523 ExtensionFileBrowserEventRouter::GetInstance()->ObserveFileSystemEvents( 524 profile_); 525 #endif 526 event_routers_initialized_ = true; 527 } 528 529 const Extension* ExtensionService::GetExtensionById( 530 const std::string& id, bool include_disabled) const { 531 return GetExtensionByIdInternal(id, true, include_disabled); 532 } 533 534 void ExtensionService::Init() { 535 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 536 537 DCHECK(!ready_); // Can't redo init. 538 DCHECK_EQ(extensions_.size(), 0u); 539 540 // Hack: we need to ensure the ResourceDispatcherHost is ready before we load 541 // the first extension, because its members listen for loaded notifications. 542 g_browser_process->resource_dispatcher_host(); 543 544 LoadAllExtensions(); 545 546 // TODO(erikkay) this should probably be deferred to a future point 547 // rather than running immediately at startup. 548 CheckForExternalUpdates(); 549 550 // TODO(erikkay) this should probably be deferred as well. 551 GarbageCollectExtensions(); 552 } 553 554 void ExtensionService::UpdateExtension(const std::string& id, 555 const FilePath& extension_path, 556 const GURL& download_url) { 557 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 558 559 PendingExtensionInfo pending_extension_info; 560 bool is_pending_extension = pending_extension_manager_.GetById( 561 id, &pending_extension_info); 562 563 const Extension* extension = GetExtensionByIdInternal(id, true, true); 564 if (!is_pending_extension && !extension) { 565 LOG(WARNING) << "Will not update extension " << id 566 << " because it is not installed or pending"; 567 // Delete extension_path since we're not creating a CrxInstaller 568 // that would do it for us. 569 BrowserThread::PostTask( 570 BrowserThread::FILE, FROM_HERE, 571 NewRunnableFunction( 572 extension_file_util::DeleteFile, extension_path, false)); 573 return; 574 } 575 576 // We want a silent install only for non-pending extensions and 577 // pending extensions that have install_silently set. 578 ExtensionInstallUI* client = 579 (!is_pending_extension || pending_extension_info.install_silently()) ? 580 NULL : new ExtensionInstallUI(profile_); 581 582 scoped_refptr<CrxInstaller> installer( 583 new CrxInstaller(this, // frontend 584 client)); 585 installer->set_expected_id(id); 586 if (is_pending_extension) 587 installer->set_install_source(pending_extension_info.install_source()); 588 else if (extension) 589 installer->set_install_source(extension->location()); 590 installer->set_delete_source(true); 591 installer->set_original_url(download_url); 592 installer->InstallCrx(extension_path); 593 } 594 595 void ExtensionService::ReloadExtension(const std::string& extension_id) { 596 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 597 FilePath path; 598 const Extension* current_extension = GetExtensionById(extension_id, false); 599 600 // Disable the extension if it's loaded. It might not be loaded if it crashed. 601 if (current_extension) { 602 // If the extension has an inspector open for its background page, detach 603 // the inspector and hang onto a cookie for it, so that we can reattach 604 // later. 605 ExtensionProcessManager* manager = profile_->GetExtensionProcessManager(); 606 ExtensionHost* host = manager->GetBackgroundHostForExtension( 607 current_extension); 608 if (host) { 609 // Look for an open inspector for the background page. 610 int devtools_cookie = DevToolsManager::GetInstance()->DetachClientHost( 611 host->render_view_host()); 612 if (devtools_cookie >= 0) 613 orphaned_dev_tools_[extension_id] = devtools_cookie; 614 } 615 616 path = current_extension->path(); 617 DisableExtension(extension_id); 618 disabled_extension_paths_[extension_id] = path; 619 } else { 620 path = unloaded_extension_paths_[extension_id]; 621 } 622 623 // Check the installed extensions to see if what we're reloading was already 624 // installed. 625 scoped_ptr<ExtensionInfo> installed_extension( 626 extension_prefs_->GetInstalledExtensionInfo(extension_id)); 627 if (installed_extension.get() && 628 installed_extension->extension_manifest.get()) { 629 LoadInstalledExtension(*installed_extension, false); 630 } else { 631 // We should always be able to remember the extension's path. If it's not in 632 // the map, someone failed to update |unloaded_extension_paths_|. 633 CHECK(!path.empty()); 634 LoadExtension(path); 635 } 636 } 637 638 bool ExtensionService::UninstallExtension(const std::string& extension_id, 639 bool external_uninstall, 640 std::string* error) { 641 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 642 643 const Extension* extension = 644 GetExtensionByIdInternal(extension_id, true, true); 645 if (!extension) 646 extension = GetTerminatedExtension(extension_id); 647 648 // Callers should not send us nonexistent extensions. 649 CHECK(extension); 650 651 // Get hold of information we need after unloading, since the extension 652 // pointer will be invalid then. 653 GURL extension_url(extension->url()); 654 Extension::Location location(extension->location()); 655 656 // Policy change which triggers an uninstall will always set 657 // |external_uninstall| to true so this is the only way to uninstall 658 // managed extensions. 659 if (!Extension::UserMayDisable(location) && !external_uninstall) { 660 NotificationService::current()->Notify( 661 NotificationType::EXTENSION_UNINSTALL_NOT_ALLOWED, 662 Source<Profile>(profile_), 663 Details<const Extension>(extension)); 664 if (error != NULL) { 665 *error = errors::kCannotUninstallManagedExtension; 666 } 667 return false; 668 } 669 670 UninstalledExtensionInfo uninstalled_extension_info(*extension); 671 672 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType", 673 extension->GetType(), 100); 674 RecordPermissionMessagesHistogram( 675 extension, "Extensions.Permissions_Uninstall"); 676 677 // Also copy the extension identifier since the reference might have been 678 // obtained via Extension::id(). 679 std::string extension_id_copy(extension_id); 680 681 if (profile_->GetTemplateURLModel()) 682 profile_->GetTemplateURLModel()->UnregisterExtensionKeyword(extension); 683 684 // Unload before doing more cleanup to ensure that nothing is hanging on to 685 // any of these resources. 686 UnloadExtension(extension_id, UnloadedExtensionInfo::UNINSTALL); 687 688 extension_prefs_->OnExtensionUninstalled(extension_id_copy, location, 689 external_uninstall); 690 691 // Tell the backend to start deleting installed extensions on the file thread. 692 if (Extension::LOAD != location) { 693 BrowserThread::PostTask( 694 BrowserThread::FILE, FROM_HERE, 695 NewRunnableFunction( 696 &extension_file_util::UninstallExtension, 697 install_directory_, 698 extension_id_copy)); 699 } 700 701 ClearExtensionData(extension_url); 702 UntrackTerminatedExtension(extension_id); 703 704 // Notify interested parties that we've uninstalled this extension. 705 NotificationService::current()->Notify( 706 NotificationType::EXTENSION_UNINSTALLED, 707 Source<Profile>(profile_), 708 Details<UninstalledExtensionInfo>(&uninstalled_extension_info)); 709 710 return true; 711 } 712 713 void ExtensionService::ClearExtensionData(const GURL& extension_url) { 714 scoped_refptr<ExtensionDataDeleter> deleter( 715 new ExtensionDataDeleter(profile_, extension_url)); 716 deleter->StartDeleting(); 717 } 718 719 bool ExtensionService::IsExtensionEnabled( 720 const std::string& extension_id) const { 721 // TODO(akalin): GetExtensionState() isn't very safe as it returns 722 // Extension::ENABLED by default; either change it to return 723 // something else by default or create a separate function that does 724 // so. 725 return 726 extension_prefs_->GetExtensionState(extension_id) == Extension::ENABLED; 727 } 728 729 bool ExtensionService::IsExternalExtensionUninstalled( 730 const std::string& extension_id) const { 731 return extension_prefs_->IsExternalExtensionUninstalled(extension_id); 732 } 733 734 void ExtensionService::EnableExtension(const std::string& extension_id) { 735 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 736 737 const Extension* extension = 738 GetExtensionByIdInternal(extension_id, false, true); 739 if (!extension) 740 return; 741 742 extension_prefs_->SetExtensionState(extension, Extension::ENABLED); 743 744 // Move it over to the enabled list. 745 extensions_.push_back(make_scoped_refptr(extension)); 746 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(), 747 disabled_extensions_.end(), 748 extension); 749 disabled_extensions_.erase(iter); 750 751 // Make sure any browser action contained within it is not hidden. 752 extension_prefs_->SetBrowserActionVisibility(extension, true); 753 754 ExtensionWebUI::RegisterChromeURLOverrides(profile_, 755 extension->GetChromeURLOverrides()); 756 757 NotifyExtensionLoaded(extension); 758 UpdateActiveExtensionsInCrashReporter(); 759 } 760 761 void ExtensionService::DisableExtension(const std::string& extension_id) { 762 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 763 764 const Extension* extension = 765 GetExtensionByIdInternal(extension_id, true, false); 766 // The extension may have been disabled already. 767 if (!extension) 768 return; 769 770 if (!Extension::UserMayDisable(extension->location())) 771 return; 772 773 extension_prefs_->SetExtensionState(extension, Extension::DISABLED); 774 775 // Move it over to the disabled list. 776 disabled_extensions_.push_back(make_scoped_refptr(extension)); 777 ExtensionList::iterator iter = std::find(extensions_.begin(), 778 extensions_.end(), 779 extension); 780 extensions_.erase(iter); 781 782 ExtensionWebUI::UnregisterChromeURLOverrides(profile_, 783 extension->GetChromeURLOverrides()); 784 785 NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::DISABLE); 786 UpdateActiveExtensionsInCrashReporter(); 787 } 788 789 void ExtensionService::GrantPermissions(const Extension* extension) { 790 CHECK(extension); 791 792 // We only maintain the granted permissions prefs for INTERNAL extensions. 793 CHECK_EQ(Extension::INTERNAL, extension->location()); 794 795 ExtensionExtent effective_hosts = extension->GetEffectiveHostPermissions(); 796 extension_prefs_->AddGrantedPermissions(extension->id(), 797 extension->HasFullPermissions(), 798 extension->api_permissions(), 799 effective_hosts); 800 } 801 802 void ExtensionService::GrantPermissionsAndEnableExtension( 803 const Extension* extension) { 804 CHECK(extension); 805 RecordPermissionMessagesHistogram( 806 extension, "Extensions.Permissions_ReEnable"); 807 GrantPermissions(extension); 808 extension_prefs_->SetDidExtensionEscalatePermissions(extension, false); 809 EnableExtension(extension->id()); 810 } 811 812 void ExtensionService::LoadExtension(const FilePath& extension_path) { 813 BrowserThread::PostTask( 814 BrowserThread::FILE, FROM_HERE, 815 NewRunnableMethod( 816 backend_.get(), 817 &ExtensionServiceBackend::LoadSingleExtension, 818 extension_path, scoped_refptr<ExtensionService>(this))); 819 } 820 821 void ExtensionService::LoadComponentExtensions() { 822 for (RegisteredComponentExtensions::iterator it = 823 component_extension_manifests_.begin(); 824 it != component_extension_manifests_.end(); ++it) { 825 LoadComponentExtension(*it); 826 } 827 } 828 829 const Extension* ExtensionService::LoadComponentExtension( 830 const ComponentExtensionInfo &info) { 831 JSONStringValueSerializer serializer(info.manifest); 832 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL)); 833 if (!manifest.get()) { 834 DLOG(ERROR) << "Failed to parse manifest for extension"; 835 return NULL; 836 } 837 838 int flags = Extension::REQUIRE_KEY; 839 if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT)) 840 flags |= Extension::STRICT_ERROR_CHECKS; 841 std::string error; 842 scoped_refptr<const Extension> extension(Extension::Create( 843 info.root_directory, 844 Extension::COMPONENT, 845 *static_cast<DictionaryValue*>(manifest.get()), 846 flags, 847 &error)); 848 if (!extension.get()) { 849 NOTREACHED() << error; 850 return NULL; 851 } 852 AddExtension(extension); 853 return extension; 854 } 855 856 void ExtensionService::LoadAllExtensions() { 857 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 858 859 base::TimeTicks start_time = base::TimeTicks::Now(); 860 861 // Load any component extensions. 862 LoadComponentExtensions(); 863 864 // Load the previously installed extensions. 865 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info( 866 extension_prefs_->GetInstalledExtensionsInfo()); 867 868 std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0); 869 bool should_write_prefs = false; 870 871 for (size_t i = 0; i < extensions_info->size(); ++i) { 872 ExtensionInfo* info = extensions_info->at(i).get(); 873 874 ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info); 875 ++reload_reason_counts[reload_reason]; 876 UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue", 877 reload_reason, 100); 878 879 if (reload_reason != NOT_NEEDED) { 880 // Reloading and extension reads files from disk. We do this on the 881 // UI thread because reloads should be very rare, and the complexity 882 // added by delaying the time when the extensions service knows about 883 // all extensions is significant. See crbug.com/37548 for details. 884 // |allow_io| disables tests that file operations run on the file 885 // thread. 886 base::ThreadRestrictions::ScopedAllowIO allow_io; 887 888 int flags = Extension::NO_FLAGS; 889 if (Extension::ShouldDoStrictErrorChecking(info->extension_location)) 890 flags |= Extension::STRICT_ERROR_CHECKS; 891 if (extension_prefs_->AllowFileAccess(info->extension_id)) 892 flags |= Extension::ALLOW_FILE_ACCESS; 893 std::string error; 894 scoped_refptr<const Extension> extension( 895 extension_file_util::LoadExtension( 896 info->extension_path, 897 info->extension_location, 898 flags, 899 &error)); 900 901 if (extension.get()) { 902 extensions_info->at(i)->extension_manifest.reset( 903 static_cast<DictionaryValue*>( 904 extension->manifest_value()->DeepCopy())); 905 should_write_prefs = true; 906 } 907 } 908 } 909 910 for (size_t i = 0; i < extensions_info->size(); ++i) { 911 LoadInstalledExtension(*extensions_info->at(i), should_write_prefs); 912 } 913 914 OnLoadedInstalledExtensions(); 915 916 // The histograms Extensions.ManifestReload* allow us to validate 917 // the assumption that reloading manifest is a rare event. 918 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded", 919 reload_reason_counts[NOT_NEEDED]); 920 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir", 921 reload_reason_counts[UNPACKED_DIR]); 922 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization", 923 reload_reason_counts[NEEDS_RELOCALIZATION]); 924 925 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll", extensions_.size()); 926 UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled", disabled_extensions_.size()); 927 928 UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime", 929 base::TimeTicks::Now() - start_time); 930 931 int app_count = 0; 932 int hosted_app_count = 0; 933 int packaged_app_count = 0; 934 int user_script_count = 0; 935 int extension_count = 0; 936 int theme_count = 0; 937 int external_count = 0; 938 int page_action_count = 0; 939 int browser_action_count = 0; 940 ExtensionList::iterator ex; 941 for (ex = extensions_.begin(); ex != extensions_.end(); ++ex) { 942 Extension::Location location = (*ex)->location(); 943 Extension::Type type = (*ex)->GetType(); 944 if ((*ex)->is_app()) { 945 UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation", 946 location, 100); 947 } else if (type == Extension::TYPE_EXTENSION) { 948 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation", 949 location, 100); 950 } 951 952 // Don't count component extensions, since they are only extensions as an 953 // implementation detail. 954 if (location == Extension::COMPONENT) 955 continue; 956 957 // Don't count unpacked extensions, since they're a developer-specific 958 // feature. 959 if (location == Extension::LOAD) 960 continue; 961 962 // Using an enumeration shows us the total installed ratio across all users. 963 // Using the totals per user at each startup tells us the distribution of 964 // usage for each user (e.g. 40% of users have at least one app installed). 965 UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100); 966 switch (type) { 967 case Extension::TYPE_THEME: 968 ++theme_count; 969 break; 970 case Extension::TYPE_USER_SCRIPT: 971 ++user_script_count; 972 break; 973 case Extension::TYPE_HOSTED_APP: 974 ++app_count; 975 ++hosted_app_count; 976 break; 977 case Extension::TYPE_PACKAGED_APP: 978 ++app_count; 979 ++packaged_app_count; 980 break; 981 case Extension::TYPE_EXTENSION: 982 default: 983 ++extension_count; 984 break; 985 } 986 if (Extension::IsExternalLocation(location)) 987 ++external_count; 988 if ((*ex)->page_action() != NULL) 989 ++page_action_count; 990 if ((*ex)->browser_action() != NULL) 991 ++browser_action_count; 992 993 RecordPermissionMessagesHistogram( 994 ex->get(), "Extensions.Permissions_Load"); 995 } 996 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp", app_count); 997 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count); 998 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count); 999 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", extension_count); 1000 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count); 1001 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count); 1002 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExternal", external_count); 1003 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count); 1004 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction", 1005 browser_action_count); 1006 } 1007 1008 // static 1009 void ExtensionService::RecordPermissionMessagesHistogram( 1010 const Extension* e, const char* histogram) { 1011 // Since this is called from multiple sources, and since the Histogram macros 1012 // use statics, we need to manually lookup the Histogram ourselves. 1013 base::Histogram* counter = base::LinearHistogram::FactoryGet( 1014 histogram, 1015 1, 1016 Extension::PermissionMessage::ID_ENUM_BOUNDARY, 1017 Extension::PermissionMessage::ID_ENUM_BOUNDARY + 1, 1018 base::Histogram::kUmaTargetedHistogramFlag); 1019 1020 std::vector<Extension::PermissionMessage> permissions = 1021 e->GetPermissionMessages(); 1022 if (permissions.empty()) { 1023 counter->Add(Extension::PermissionMessage::ID_NONE); 1024 } else { 1025 std::vector<Extension::PermissionMessage>::iterator it; 1026 for (it = permissions.begin(); it != permissions.end(); ++it) 1027 counter->Add(it->message_id()); 1028 } 1029 } 1030 1031 void ExtensionService::LoadInstalledExtension(const ExtensionInfo& info, 1032 bool write_to_prefs) { 1033 std::string error; 1034 scoped_refptr<const Extension> extension(NULL); 1035 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) { 1036 error = errors::kDisabledByPolicy; 1037 } else if (info.extension_manifest.get()) { 1038 int flags = Extension::NO_FLAGS; 1039 if (info.extension_location != Extension::LOAD) 1040 flags |= Extension::REQUIRE_KEY; 1041 if (Extension::ShouldDoStrictErrorChecking(info.extension_location)) 1042 flags |= Extension::STRICT_ERROR_CHECKS; 1043 if (extension_prefs_->AllowFileAccess(info.extension_id)) 1044 flags |= Extension::ALLOW_FILE_ACCESS; 1045 extension = Extension::Create( 1046 info.extension_path, 1047 info.extension_location, 1048 *info.extension_manifest, 1049 flags, 1050 &error); 1051 } else { 1052 error = errors::kManifestUnreadable; 1053 } 1054 1055 if (!extension) { 1056 ReportExtensionLoadError(info.extension_path, 1057 error, 1058 NotificationType::EXTENSION_INSTALL_ERROR, 1059 false); 1060 return; 1061 } 1062 1063 if (write_to_prefs) 1064 extension_prefs_->UpdateManifest(extension); 1065 1066 AddExtension(extension); 1067 } 1068 1069 void ExtensionService::NotifyExtensionLoaded(const Extension* extension) { 1070 // The ChromeURLRequestContexts need to be first to know that the extension 1071 // was loaded, otherwise a race can arise where a renderer that is created 1072 // for the extension may try to load an extension URL with an extension id 1073 // that the request context doesn't yet know about. The profile is responsible 1074 // for ensuring its URLRequestContexts appropriately discover the loaded 1075 // extension. 1076 if (profile_) { 1077 profile_->RegisterExtensionWithRequestContexts(extension); 1078 profile_->GetExtensionSpecialStoragePolicy()-> 1079 GrantRightsForExtension(extension); 1080 } 1081 1082 NotificationService::current()->Notify( 1083 NotificationType::EXTENSION_LOADED, 1084 Source<Profile>(profile_), 1085 Details<const Extension>(extension)); 1086 1087 bool plugins_changed = false; 1088 for (size_t i = 0; i < extension->plugins().size(); ++i) { 1089 const Extension::PluginInfo& plugin = extension->plugins()[i]; 1090 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); 1091 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(plugin.path); 1092 plugins_changed = true; 1093 if (!plugin.is_public) { 1094 PluginService::GetInstance()->RestrictPluginToUrl( 1095 plugin.path, extension->url()); 1096 } 1097 } 1098 1099 bool nacl_modules_changed = false; 1100 for (size_t i = 0; i < extension->nacl_modules().size(); ++i) { 1101 const Extension::NaClModuleInfo& module = extension->nacl_modules()[i]; 1102 RegisterNaClModule(module.url, module.mime_type); 1103 nacl_modules_changed = true; 1104 } 1105 1106 if (nacl_modules_changed) 1107 UpdatePluginListWithNaClModules(); 1108 1109 if (plugins_changed || nacl_modules_changed) 1110 PluginService::GetInstance()->PurgePluginListCache(false); 1111 } 1112 1113 void ExtensionService::NotifyExtensionUnloaded( 1114 const Extension* extension, UnloadedExtensionInfo::Reason reason) { 1115 UnloadedExtensionInfo details(extension, reason); 1116 NotificationService::current()->Notify( 1117 NotificationType::EXTENSION_UNLOADED, 1118 Source<Profile>(profile_), 1119 Details<UnloadedExtensionInfo>(&details)); 1120 1121 if (profile_) { 1122 profile_->UnregisterExtensionWithRequestContexts(extension->id(), reason); 1123 profile_->GetExtensionSpecialStoragePolicy()-> 1124 RevokeRightsForExtension(extension); 1125 #if defined(OS_CHROMEOS) 1126 // Revoke external file access to 1127 if (profile_->GetFileSystemContext() && 1128 profile_->GetFileSystemContext()->path_manager() && 1129 profile_->GetFileSystemContext()->path_manager()->external_provider()) { 1130 profile_->GetFileSystemContext()->path_manager()->external_provider()-> 1131 RevokeAccessForExtension(extension->id()); 1132 } 1133 #endif 1134 } 1135 1136 bool plugins_changed = false; 1137 for (size_t i = 0; i < extension->plugins().size(); ++i) { 1138 const Extension::PluginInfo& plugin = extension->plugins()[i]; 1139 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 1140 NewRunnableFunction(&ForceShutdownPlugin, 1141 plugin.path)); 1142 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); 1143 webkit::npapi::PluginList::Singleton()->RemoveExtraPluginPath( 1144 plugin.path); 1145 plugins_changed = true; 1146 if (!plugin.is_public) 1147 PluginService::GetInstance()->RestrictPluginToUrl(plugin.path, GURL()); 1148 } 1149 1150 bool nacl_modules_changed = false; 1151 for (size_t i = 0; i < extension->nacl_modules().size(); ++i) { 1152 const Extension::NaClModuleInfo& module = extension->nacl_modules()[i]; 1153 UnregisterNaClModule(module.url); 1154 nacl_modules_changed = true; 1155 } 1156 1157 if (nacl_modules_changed) 1158 UpdatePluginListWithNaClModules(); 1159 1160 if (plugins_changed || nacl_modules_changed) 1161 PluginService::GetInstance()->PurgePluginListCache(false); 1162 } 1163 1164 void ExtensionService::UpdateExtensionBlacklist( 1165 const std::vector<std::string>& blacklist) { 1166 // Use this set to indicate if an extension in the blacklist has been used. 1167 std::set<std::string> blacklist_set; 1168 for (unsigned int i = 0; i < blacklist.size(); ++i) { 1169 if (Extension::IdIsValid(blacklist[i])) { 1170 blacklist_set.insert(blacklist[i]); 1171 } 1172 } 1173 extension_prefs_->UpdateBlacklist(blacklist_set); 1174 std::vector<std::string> to_be_removed; 1175 // Loop current extensions, unload installed extensions. 1176 for (ExtensionList::const_iterator iter = extensions_.begin(); 1177 iter != extensions_.end(); ++iter) { 1178 const Extension* extension = (*iter); 1179 if (blacklist_set.find(extension->id()) != blacklist_set.end()) { 1180 to_be_removed.push_back(extension->id()); 1181 } 1182 } 1183 1184 // UnloadExtension will change the extensions_ list. So, we should 1185 // call it outside the iterator loop. 1186 for (unsigned int i = 0; i < to_be_removed.size(); ++i) { 1187 UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::DISABLE); 1188 } 1189 } 1190 1191 Profile* ExtensionService::profile() { 1192 return profile_; 1193 } 1194 1195 void ExtensionService::DestroyingProfile() { 1196 if (updater_.get()) { 1197 updater_->Stop(); 1198 } 1199 browser_event_router_.reset(); 1200 preference_event_router_.reset(); 1201 pref_change_registrar_.RemoveAll(); 1202 profile_ = NULL; 1203 toolbar_model_.DestroyingProfile(); 1204 } 1205 1206 ExtensionPrefs* ExtensionService::extension_prefs() { 1207 return extension_prefs_; 1208 } 1209 1210 ExtensionUpdater* ExtensionService::updater() { 1211 return updater_.get(); 1212 } 1213 1214 void ExtensionService::CheckAdminBlacklist() { 1215 std::vector<std::string> to_be_removed; 1216 // Loop through extensions list, unload installed extensions. 1217 for (ExtensionList::const_iterator iter = extensions_.begin(); 1218 iter != extensions_.end(); ++iter) { 1219 const Extension* extension = (*iter); 1220 if (!extension_prefs_->IsExtensionAllowedByPolicy(extension->id())) 1221 to_be_removed.push_back(extension->id()); 1222 } 1223 1224 // UnloadExtension will change the extensions_ list. So, we should 1225 // call it outside the iterator loop. 1226 for (unsigned int i = 0; i < to_be_removed.size(); ++i) 1227 UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::DISABLE); 1228 } 1229 1230 void ExtensionService::CheckForUpdatesSoon() { 1231 if (updater()) { 1232 updater()->CheckSoon(); 1233 } else { 1234 LOG(WARNING) << "CheckForUpdatesSoon() called with auto-update turned off"; 1235 } 1236 } 1237 1238 void ExtensionService::ProcessSyncData( 1239 const ExtensionSyncData& extension_sync_data, 1240 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow) { 1241 const std::string& id = extension_sync_data.id; 1242 1243 // Handle uninstalls first. 1244 if (extension_sync_data.uninstalled) { 1245 std::string error; 1246 if (!UninstallExtensionHelper(this, id)) { 1247 LOG(WARNING) << "Could not uninstall extension " << id 1248 << " for sync"; 1249 } 1250 return; 1251 } 1252 1253 const Extension* extension = GetExtensionByIdInternal(id, true, true); 1254 // TODO(akalin): Figure out what to do with terminated extensions. 1255 1256 // Handle already-installed extensions (just update settings). 1257 // 1258 // TODO(akalin): Ideally, we should be able to set prefs for an 1259 // extension regardless of whether or not it's installed (and have 1260 // it automatially apply on install). 1261 if (extension) { 1262 if (extension_sync_data.enabled) { 1263 EnableExtension(id); 1264 } else { 1265 DisableExtension(id); 1266 } 1267 SetIsIncognitoEnabled(id, extension_sync_data.incognito_enabled); 1268 int result = extension->version()->CompareTo(extension_sync_data.version); 1269 if (result < 0) { 1270 // Extension is outdated. 1271 CheckForUpdatesSoon(); 1272 } else if (result > 0) { 1273 // Sync version is outdated. Do nothing for now, as sync code 1274 // in other places will eventually update the sync data. 1275 // 1276 // TODO(akalin): Move that code here. 1277 } 1278 return; 1279 } 1280 1281 // Handle not-yet-installed extensions. 1282 // 1283 // TODO(akalin): Replace silent update with a list of enabled 1284 // permissions. 1285 pending_extension_manager()->AddFromSync( 1286 id, 1287 extension_sync_data.update_url, 1288 should_allow, 1289 true, // install_silently 1290 extension_sync_data.enabled, 1291 extension_sync_data.incognito_enabled); 1292 CheckForUpdatesSoon(); 1293 } 1294 1295 bool ExtensionService::IsIncognitoEnabled( 1296 const std::string& extension_id) const { 1297 // If this is an existing component extension we always allow it to 1298 // work in incognito mode. 1299 const Extension* extension = GetExtensionById(extension_id, true); 1300 if (extension && extension->location() == Extension::COMPONENT) 1301 return true; 1302 1303 // Check the prefs. 1304 return extension_prefs_->IsIncognitoEnabled(extension_id); 1305 } 1306 1307 void ExtensionService::SetIsIncognitoEnabled( 1308 const std::string& extension_id, bool enabled) { 1309 const Extension* extension = GetExtensionById(extension_id, false); 1310 if (extension && extension->location() == Extension::COMPONENT) { 1311 // This shouldn't be called for component extensions. 1312 NOTREACHED(); 1313 return; 1314 } 1315 1316 // Broadcast unloaded and loaded events to update browser state. Only bother 1317 // if the value changed and the extension is actually enabled, since there is 1318 // no UI otherwise. 1319 bool old_enabled = extension_prefs_->IsIncognitoEnabled(extension_id); 1320 if (enabled == old_enabled) 1321 return; 1322 1323 extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled); 1324 if (extension) { 1325 NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::DISABLE); 1326 NotifyExtensionLoaded(extension); 1327 } 1328 } 1329 1330 bool ExtensionService::CanCrossIncognito(const Extension* extension) { 1331 // We allow the extension to see events and data from another profile iff it 1332 // uses "spanning" behavior and it has incognito access. "split" mode 1333 // extensions only see events for a matching profile. 1334 return IsIncognitoEnabled(extension->id()) && 1335 !extension->incognito_split_mode(); 1336 } 1337 1338 bool ExtensionService::AllowFileAccess(const Extension* extension) { 1339 return (CommandLine::ForCurrentProcess()->HasSwitch( 1340 switches::kDisableExtensionsFileAccessCheck) || 1341 extension_prefs_->AllowFileAccess(extension->id())); 1342 } 1343 1344 void ExtensionService::SetAllowFileAccess(const Extension* extension, 1345 bool allow) { 1346 // Reload to update browser state. Only bother if the value changed and the 1347 // extension is actually enabled, since there is no UI otherwise. 1348 bool old_allow = AllowFileAccess(extension); 1349 if (allow == old_allow) 1350 return; 1351 1352 extension_prefs_->SetAllowFileAccess(extension->id(), allow); 1353 1354 bool extension_is_enabled = std::find(extensions_.begin(), extensions_.end(), 1355 extension) != extensions_.end(); 1356 if (extension_is_enabled) 1357 ReloadExtension(extension->id()); 1358 } 1359 1360 bool ExtensionService::GetBrowserActionVisibility(const Extension* extension) { 1361 return extension_prefs_->GetBrowserActionVisibility(extension); 1362 } 1363 1364 void ExtensionService::SetBrowserActionVisibility(const Extension* extension, 1365 bool visible) { 1366 extension_prefs_->SetBrowserActionVisibility(extension, visible); 1367 } 1368 1369 // Some extensions will autoupdate themselves externally from Chrome. These 1370 // are typically part of some larger client application package. To support 1371 // these, the extension will register its location in the the preferences file 1372 // (and also, on Windows, in the registry) and this code will periodically 1373 // check that location for a .crx file, which it will then install locally if 1374 // a new version is available. 1375 // Errors are reported through ExtensionErrorReporter. Succcess is not 1376 // reported. 1377 void ExtensionService::CheckForExternalUpdates() { 1378 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1379 1380 // Note that this installation is intentionally silent (since it didn't 1381 // go through the front-end). Extensions that are registered in this 1382 // way are effectively considered 'pre-bundled', and so implicitly 1383 // trusted. In general, if something has HKLM or filesystem access, 1384 // they could install an extension manually themselves anyway. 1385 1386 // If any external extension records give a URL, a provider will set 1387 // this to true. Used by OnExternalProviderReady() to see if we need 1388 // to start an update check to fetch a new external extension. 1389 external_extension_url_added_ = false; 1390 1391 // Ask each external extension provider to give us a call back for each 1392 // extension they know about. See OnExternalExtension(File|UpdateUrl)Found. 1393 ProviderCollection::const_iterator i; 1394 for (i = external_extension_providers_.begin(); 1395 i != external_extension_providers_.end(); ++i) { 1396 ExternalExtensionProviderInterface* provider = i->get(); 1397 provider->VisitRegisteredExtension(); 1398 } 1399 1400 // Uninstall of unclaimed extensions will happen after all the providers 1401 // had reported ready. Every provider calls OnExternalProviderReady() 1402 // when it finishes, and OnExternalProviderReady() only acts when all 1403 // providers are ready. In case there are no providers, we call it 1404 // to trigger removal of extensions that used to have an external source. 1405 if (external_extension_providers_.empty()) 1406 OnExternalProviderReady(); 1407 } 1408 1409 void ExtensionService::OnExternalProviderReady() { 1410 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1411 1412 // An external provider has finished loading. We only take action 1413 // if all of them are finished. So we check them first. 1414 ProviderCollection::const_iterator i; 1415 for (i = external_extension_providers_.begin(); 1416 i != external_extension_providers_.end(); ++i) { 1417 ExternalExtensionProviderInterface* provider = i->get(); 1418 if (!provider->IsReady()) 1419 return; 1420 } 1421 1422 // All the providers are ready. Install any pending extensions. 1423 if (external_extension_url_added_ && updater()) { 1424 external_extension_url_added_ = false; 1425 updater()->CheckNow(); 1426 } 1427 1428 // Uninstall all the unclaimed extensions. 1429 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info( 1430 extension_prefs_->GetInstalledExtensionsInfo()); 1431 for (size_t i = 0; i < extensions_info->size(); ++i) { 1432 ExtensionInfo* info = extensions_info->at(i).get(); 1433 if (Extension::IsExternalLocation(info->extension_location)) 1434 CheckExternalUninstall(info->extension_id); 1435 } 1436 } 1437 1438 void ExtensionService::UnloadExtension( 1439 const std::string& extension_id, 1440 UnloadedExtensionInfo::Reason reason) { 1441 // Make sure the extension gets deleted after we return from this function. 1442 scoped_refptr<const Extension> extension( 1443 GetExtensionByIdInternal(extension_id, true, true)); 1444 1445 // This method can be called via PostTask, so the extension may have been 1446 // unloaded by the time this runs. 1447 if (!extension) { 1448 // In case the extension may have crashed/uninstalled. Allow the profile to 1449 // clean up its RequestContexts. 1450 profile_->UnregisterExtensionWithRequestContexts(extension_id, reason); 1451 return; 1452 } 1453 1454 // Keep information about the extension so that we can reload it later 1455 // even if it's not permanently installed. 1456 unloaded_extension_paths_[extension->id()] = extension->path(); 1457 1458 // Clean up if the extension is meant to be enabled after a reload. 1459 disabled_extension_paths_.erase(extension->id()); 1460 1461 // Clean up runtime data. 1462 extension_runtime_data_.erase(extension_id); 1463 1464 ExtensionWebUI::UnregisterChromeURLOverrides(profile_, 1465 extension->GetChromeURLOverrides()); 1466 1467 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(), 1468 disabled_extensions_.end(), 1469 extension.get()); 1470 if (iter != disabled_extensions_.end()) { 1471 UnloadedExtensionInfo details(extension, reason); 1472 details.already_disabled = true; 1473 disabled_extensions_.erase(iter); 1474 NotificationService::current()->Notify( 1475 NotificationType::EXTENSION_UNLOADED, 1476 Source<Profile>(profile_), 1477 Details<UnloadedExtensionInfo>(&details)); 1478 // Make sure the profile cleans up its RequestContexts when an already 1479 // disabled extension is unloaded (since they are also tracking the disabled 1480 // extensions). 1481 profile_->UnregisterExtensionWithRequestContexts(extension_id, reason); 1482 return; 1483 } 1484 1485 iter = std::find(extensions_.begin(), extensions_.end(), extension.get()); 1486 1487 // Remove the extension from our list. 1488 extensions_.erase(iter); 1489 1490 NotifyExtensionUnloaded(extension.get(), reason); 1491 UpdateActiveExtensionsInCrashReporter(); 1492 } 1493 1494 void ExtensionService::UnloadAllExtensions() { 1495 if (profile_) { 1496 profile_->GetExtensionSpecialStoragePolicy()-> 1497 RevokeRightsForAllExtensions(); 1498 } 1499 extensions_.clear(); 1500 disabled_extensions_.clear(); 1501 terminated_extension_ids_.clear(); 1502 terminated_extensions_.clear(); 1503 extension_runtime_data_.clear(); 1504 1505 // TODO(erikkay) should there be a notification for this? We can't use 1506 // EXTENSION_UNLOADED since that implies that the extension has been disabled 1507 // or uninstalled, and UnloadAll is just part of shutdown. 1508 } 1509 1510 void ExtensionService::ReloadExtensions() { 1511 UnloadAllExtensions(); 1512 LoadAllExtensions(); 1513 } 1514 1515 void ExtensionService::GarbageCollectExtensions() { 1516 if (extension_prefs_->pref_service()->ReadOnly()) 1517 return; 1518 1519 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info( 1520 extension_prefs_->GetInstalledExtensionsInfo()); 1521 1522 std::map<std::string, FilePath> extension_paths; 1523 for (size_t i = 0; i < info->size(); ++i) 1524 extension_paths[info->at(i)->extension_id] = info->at(i)->extension_path; 1525 1526 BrowserThread::PostTask( 1527 BrowserThread::FILE, FROM_HERE, 1528 NewRunnableFunction( 1529 &extension_file_util::GarbageCollectExtensions, install_directory_, 1530 extension_paths)); 1531 1532 // Also garbage-collect themes. We check |profile_| to be 1533 // defensive; in the future, we may call GarbageCollectExtensions() 1534 // from somewhere other than Init() (e.g., in a timer). 1535 if (profile_) { 1536 ThemeServiceFactory::GetForProfile(profile_)->RemoveUnusedThemes(); 1537 } 1538 } 1539 1540 void ExtensionService::OnLoadedInstalledExtensions() { 1541 if (updater_.get()) { 1542 updater_->Start(); 1543 } 1544 1545 ready_ = true; 1546 NotificationService::current()->Notify( 1547 NotificationType::EXTENSIONS_READY, 1548 Source<Profile>(profile_), 1549 NotificationService::NoDetails()); 1550 } 1551 1552 void ExtensionService::AddExtension(const Extension* extension) { 1553 // Ensure extension is deleted unless we transfer ownership. 1554 scoped_refptr<const Extension> scoped_extension(extension); 1555 1556 // The extension is now loaded, remove its data from unloaded extension map. 1557 unloaded_extension_paths_.erase(extension->id()); 1558 1559 // If a terminated extension is loaded, remove it from the terminated list. 1560 UntrackTerminatedExtension(extension->id()); 1561 1562 // If the extension was disabled for a reload, then enable it. 1563 if (disabled_extension_paths_.erase(extension->id()) > 0) 1564 EnableExtension(extension->id()); 1565 1566 // TODO(jstritar): We may be able to get rid of this branch by overriding the 1567 // default extension state to DISABLED when the --disable-extensions flag 1568 // is set (http://crbug.com/29067). 1569 if (!extensions_enabled() && 1570 !extension->is_theme() && 1571 extension->location() != Extension::COMPONENT && 1572 !Extension::IsExternalLocation(extension->location())) 1573 return; 1574 1575 // Check if the extension's privileges have changed and disable the 1576 // extension if necessary. 1577 DisableIfPrivilegeIncrease(extension); 1578 1579 switch (extension_prefs_->GetExtensionState(extension->id())) { 1580 case Extension::ENABLED: 1581 extensions_.push_back(scoped_extension); 1582 1583 NotifyExtensionLoaded(extension); 1584 1585 ExtensionWebUI::RegisterChromeURLOverrides( 1586 profile_, extension->GetChromeURLOverrides()); 1587 break; 1588 case Extension::DISABLED: 1589 disabled_extensions_.push_back(scoped_extension); 1590 NotificationService::current()->Notify( 1591 NotificationType::EXTENSION_UPDATE_DISABLED, 1592 Source<Profile>(profile_), 1593 Details<const Extension>(extension)); 1594 break; 1595 default: 1596 NOTREACHED(); 1597 break; 1598 } 1599 1600 SetBeingUpgraded(extension, false); 1601 1602 UpdateActiveExtensionsInCrashReporter(); 1603 1604 if (profile_->GetTemplateURLModel()) 1605 profile_->GetTemplateURLModel()->RegisterExtensionKeyword(extension); 1606 1607 // Load the icon for omnibox-enabled extensions so it will be ready to display 1608 // in the URL bar. 1609 if (!extension->omnibox_keyword().empty()) { 1610 omnibox_popup_icon_manager_.LoadIcon(extension); 1611 omnibox_icon_manager_.LoadIcon(extension); 1612 } 1613 } 1614 1615 void ExtensionService::DisableIfPrivilegeIncrease(const Extension* extension) { 1616 // We keep track of all permissions the user has granted each extension. 1617 // This allows extensions to gracefully support backwards compatibility 1618 // by including unknown permissions in their manifests. When the user 1619 // installs the extension, only the recognized permissions are recorded. 1620 // When the unknown permissions become recognized (e.g., through browser 1621 // upgrade), we can prompt the user to accept these new permissions. 1622 // Extensions can also silently upgrade to less permissions, and then 1623 // silently upgrade to a version that adds these permissions back. 1624 // 1625 // For example, pretend that Chrome 10 includes a permission "omnibox" 1626 // for an API that adds suggestions to the omnibox. An extension can 1627 // maintain backwards compatibility while still having "omnibox" in the 1628 // manifest. If a user installs the extension on Chrome 9, the browser 1629 // will record the permissions it recognized, not including "omnibox." 1630 // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome 1631 // will disable the extension and prompt the user to approve the increase 1632 // in privileges. The extension could then release a new version that 1633 // removes the "omnibox" permission. When the user upgrades, Chrome will 1634 // still remember that "omnibox" had been granted, so that if the 1635 // extension once again includes "omnibox" in an upgrade, the extension 1636 // can upgrade without requiring this user's approval. 1637 const Extension* old = GetExtensionByIdInternal(extension->id(), 1638 true, true); 1639 bool granted_full_access; 1640 std::set<std::string> granted_apis; 1641 ExtensionExtent granted_extent; 1642 1643 bool is_extension_upgrade = old != NULL; 1644 bool is_privilege_increase = false; 1645 1646 // We only record the granted permissions for INTERNAL extensions, since 1647 // they can't silently increase privileges. 1648 if (extension->location() == Extension::INTERNAL) { 1649 // Add all the recognized permissions if the granted permissions list 1650 // hasn't been initialized yet. 1651 if (!extension_prefs_->GetGrantedPermissions(extension->id(), 1652 &granted_full_access, 1653 &granted_apis, 1654 &granted_extent)) { 1655 GrantPermissions(extension); 1656 CHECK(extension_prefs_->GetGrantedPermissions(extension->id(), 1657 &granted_full_access, 1658 &granted_apis, 1659 &granted_extent)); 1660 } 1661 1662 // Here, we check if an extension's privileges have increased in a manner 1663 // that requires the user's approval. This could occur because the browser 1664 // upgraded and recognized additional privileges, or an extension upgrades 1665 // to a version that requires additional privileges. 1666 is_privilege_increase = Extension::IsPrivilegeIncrease( 1667 granted_full_access, granted_apis, granted_extent, extension); 1668 } 1669 1670 if (is_extension_upgrade) { 1671 // Other than for unpacked extensions, CrxInstaller should have guaranteed 1672 // that we aren't downgrading. 1673 if (extension->location() != Extension::LOAD) 1674 CHECK(extension->version()->CompareTo(*(old->version())) >= 0); 1675 1676 // Extensions get upgraded if the privileges are allowed to increase or 1677 // the privileges haven't increased. 1678 if (!is_privilege_increase) { 1679 SetBeingUpgraded(old, true); 1680 SetBeingUpgraded(extension, true); 1681 } 1682 1683 // To upgrade an extension in place, unload the old one and 1684 // then load the new one. 1685 UnloadExtension(old->id(), UnloadedExtensionInfo::UPDATE); 1686 old = NULL; 1687 } 1688 1689 // Extension has changed permissions significantly. Disable it. A 1690 // notification should be sent by the caller. 1691 if (is_privilege_increase) { 1692 if (!extension_prefs_->DidExtensionEscalatePermissions(extension->id())) { 1693 RecordPermissionMessagesHistogram( 1694 extension, "Extensions.Permissions_AutoDisable"); 1695 } 1696 extension_prefs_->SetExtensionState(extension, Extension::DISABLED); 1697 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); 1698 } 1699 } 1700 1701 void ExtensionService::UpdateActiveExtensionsInCrashReporter() { 1702 std::set<std::string> extension_ids; 1703 for (size_t i = 0; i < extensions_.size(); ++i) { 1704 if (!extensions_[i]->is_theme() && 1705 extensions_[i]->location() != Extension::COMPONENT) 1706 extension_ids.insert(extensions_[i]->id()); 1707 } 1708 1709 child_process_logging::SetActiveExtensions(extension_ids); 1710 } 1711 1712 void ExtensionService::OnExtensionInstalled(const Extension* extension) { 1713 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1714 1715 // Ensure extension is deleted unless we transfer ownership. 1716 scoped_refptr<const Extension> scoped_extension(extension); 1717 const std::string& id = extension->id(); 1718 bool initial_enable = false; 1719 bool initial_enable_incognito = false; 1720 1721 PendingExtensionInfo pending_extension_info; 1722 if (pending_extension_manager()->GetById(id, &pending_extension_info)) { 1723 pending_extension_manager()->Remove(id); 1724 1725 if (!pending_extension_info.ShouldAllowInstall(*extension)) { 1726 LOG(WARNING) 1727 << "ShouldAllowInstall() returned false for " 1728 << id << " of type " << extension->GetType() 1729 << " and update URL " << extension->update_url().spec() 1730 << "; not installing"; 1731 1732 NotificationService::current()->Notify( 1733 NotificationType::EXTENSION_INSTALL_NOT_ALLOWED, 1734 Source<Profile>(profile_), 1735 Details<const Extension>(extension)); 1736 1737 // Delete the extension directory since we're not going to 1738 // load it. 1739 BrowserThread::PostTask( 1740 BrowserThread::FILE, FROM_HERE, 1741 NewRunnableFunction(&extension_file_util::DeleteFile, 1742 extension->path(), true)); 1743 return; 1744 } 1745 1746 if (extension->is_theme()) { 1747 DCHECK(pending_extension_info.enable_on_install()); 1748 initial_enable = true; 1749 DCHECK(!pending_extension_info.enable_incognito_on_install()); 1750 initial_enable_incognito = false; 1751 } else { 1752 initial_enable = pending_extension_info.enable_on_install(); 1753 initial_enable_incognito = 1754 pending_extension_info.enable_incognito_on_install(); 1755 } 1756 } else { 1757 // We explicitly want to re-enable an uninstalled external 1758 // extension; if we're here, that means the user is manually 1759 // installing the extension. 1760 initial_enable = 1761 IsExtensionEnabled(id) || IsExternalExtensionUninstalled(id); 1762 initial_enable_incognito = IsIncognitoEnabled(id); 1763 } 1764 1765 UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType", 1766 extension->GetType(), 100); 1767 RecordPermissionMessagesHistogram( 1768 extension, "Extensions.Permissions_Install"); 1769 ShownSectionsHandler::OnExtensionInstalled(profile_->GetPrefs(), extension); 1770 extension_prefs_->OnExtensionInstalled( 1771 extension, initial_enable ? Extension::ENABLED : Extension::DISABLED, 1772 initial_enable_incognito); 1773 1774 // Unpacked extensions default to allowing file access, but if that has been 1775 // overridden, don't reset the value. 1776 if (Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD) && 1777 !extension_prefs_->HasAllowFileAccessSetting(id)) { 1778 extension_prefs_->SetAllowFileAccess(id, true); 1779 } 1780 1781 NotificationService::current()->Notify( 1782 NotificationType::EXTENSION_INSTALLED, 1783 Source<Profile>(profile_), 1784 Details<const Extension>(extension)); 1785 1786 // Transfer ownership of |extension| to AddExtension. 1787 AddExtension(scoped_extension); 1788 } 1789 1790 const Extension* ExtensionService::GetExtensionByIdInternal( 1791 const std::string& id, bool include_enabled, bool include_disabled) const { 1792 std::string lowercase_id = StringToLowerASCII(id); 1793 if (include_enabled) { 1794 for (ExtensionList::const_iterator iter = extensions_.begin(); 1795 iter != extensions_.end(); ++iter) { 1796 if ((*iter)->id() == lowercase_id) 1797 return *iter; 1798 } 1799 } 1800 if (include_disabled) { 1801 for (ExtensionList::const_iterator iter = disabled_extensions_.begin(); 1802 iter != disabled_extensions_.end(); ++iter) { 1803 if ((*iter)->id() == lowercase_id) 1804 return *iter; 1805 } 1806 } 1807 return NULL; 1808 } 1809 1810 void ExtensionService::TrackTerminatedExtension(const Extension* extension) { 1811 if (terminated_extension_ids_.insert(extension->id()).second) 1812 terminated_extensions_.push_back(make_scoped_refptr(extension)); 1813 } 1814 1815 void ExtensionService::UntrackTerminatedExtension(const std::string& id) { 1816 if (terminated_extension_ids_.erase(id) <= 0) 1817 return; 1818 1819 std::string lowercase_id = StringToLowerASCII(id); 1820 for (ExtensionList::iterator iter = terminated_extensions_.begin(); 1821 iter != terminated_extensions_.end(); ++iter) { 1822 if ((*iter)->id() == lowercase_id) { 1823 terminated_extensions_.erase(iter); 1824 return; 1825 } 1826 } 1827 } 1828 1829 const Extension* ExtensionService::GetTerminatedExtension( 1830 const std::string& id) { 1831 std::string lowercase_id = StringToLowerASCII(id); 1832 for (ExtensionList::const_iterator iter = terminated_extensions_.begin(); 1833 iter != terminated_extensions_.end(); ++iter) { 1834 if ((*iter)->id() == lowercase_id) 1835 return *iter; 1836 } 1837 return NULL; 1838 } 1839 1840 const Extension* ExtensionService::GetWebStoreApp() { 1841 return GetExtensionById(extension_misc::kWebStoreAppId, false); 1842 } 1843 1844 const Extension* ExtensionService::GetExtensionByURL(const GURL& url) { 1845 return url.scheme() != chrome::kExtensionScheme ? NULL : 1846 GetExtensionById(url.host(), false); 1847 } 1848 1849 const Extension* ExtensionService::GetExtensionByWebExtent(const GURL& url) { 1850 for (size_t i = 0; i < extensions_.size(); ++i) { 1851 if (extensions_[i]->web_extent().ContainsURL(url)) 1852 return extensions_[i]; 1853 } 1854 return NULL; 1855 } 1856 1857 bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) { 1858 // Allow bindings for all packaged extension. 1859 if (GetExtensionByURL(url)) 1860 return true; 1861 1862 // Allow bindings for all component, hosted apps. 1863 const Extension* extension = GetExtensionByWebExtent(url); 1864 return (extension && extension->location() == Extension::COMPONENT); 1865 } 1866 1867 const Extension* ExtensionService::GetExtensionByOverlappingWebExtent( 1868 const ExtensionExtent& extent) { 1869 for (size_t i = 0; i < extensions_.size(); ++i) { 1870 if (extensions_[i]->web_extent().OverlapsWith(extent)) 1871 return extensions_[i]; 1872 } 1873 1874 return NULL; 1875 } 1876 1877 const SkBitmap& ExtensionService::GetOmniboxIcon( 1878 const std::string& extension_id) { 1879 return omnibox_icon_manager_.GetIcon(extension_id); 1880 } 1881 1882 const SkBitmap& ExtensionService::GetOmniboxPopupIcon( 1883 const std::string& extension_id) { 1884 return omnibox_popup_icon_manager_.GetIcon(extension_id); 1885 } 1886 1887 void ExtensionService::OnExternalExtensionFileFound( 1888 const std::string& id, 1889 const Version* version, 1890 const FilePath& path, 1891 Extension::Location location) { 1892 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1893 CHECK(Extension::IdIsValid(id)); 1894 if (extension_prefs_->IsExternalExtensionUninstalled(id)) 1895 return; 1896 1897 DCHECK(version); 1898 1899 // Before even bothering to unpack, check and see if we already have this 1900 // version. This is important because these extensions are going to get 1901 // installed on every startup. 1902 const Extension* existing = GetExtensionById(id, true); 1903 if (existing) { 1904 switch (existing->version()->CompareTo(*version)) { 1905 case -1: // existing version is older, we should upgrade 1906 break; 1907 case 0: // existing version is same, do nothing 1908 return; 1909 case 1: // existing version is newer, uh-oh 1910 LOG(WARNING) << "Found external version of extension " << id 1911 << "that is older than current version. Current version " 1912 << "is: " << existing->VersionString() << ". New version " 1913 << "is: " << version << ". Keeping current version."; 1914 return; 1915 } 1916 } 1917 1918 pending_extension_manager()->AddFromExternalFile(id, location); 1919 1920 scoped_refptr<CrxInstaller> installer( 1921 new CrxInstaller(this, // frontend 1922 NULL)); // no client (silent install) 1923 installer->set_install_source(location); 1924 installer->set_expected_id(id); 1925 installer->set_expected_version(*version), 1926 installer->InstallCrx(path); 1927 } 1928 1929 void ExtensionService::ReportExtensionLoadError( 1930 const FilePath& extension_path, 1931 const std::string &error, 1932 NotificationType type, 1933 bool be_noisy) { 1934 NotificationService* service = NotificationService::current(); 1935 service->Notify(type, 1936 Source<Profile>(profile_), 1937 Details<const std::string>(&error)); 1938 1939 std::string path_str = UTF16ToUTF8(extension_path.LossyDisplayName()); 1940 std::string message = base::StringPrintf( 1941 "Could not load extension from '%s'. %s", 1942 path_str.c_str(), error.c_str()); 1943 ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy); 1944 } 1945 1946 void ExtensionService::DidCreateRenderViewForBackgroundPage( 1947 ExtensionHost* host) { 1948 OrphanedDevTools::iterator iter = 1949 orphaned_dev_tools_.find(host->extension_id()); 1950 if (iter == orphaned_dev_tools_.end()) 1951 return; 1952 1953 DevToolsManager::GetInstance()->AttachClientHost( 1954 iter->second, host->render_view_host()); 1955 orphaned_dev_tools_.erase(iter); 1956 } 1957 1958 void ExtensionService::Observe(NotificationType type, 1959 const NotificationSource& source, 1960 const NotificationDetails& details) { 1961 switch (type.value) { 1962 case NotificationType::EXTENSION_PROCESS_TERMINATED: { 1963 if (profile_ != Source<Profile>(source).ptr()->GetOriginalProfile()) 1964 break; 1965 1966 ExtensionHost* host = Details<ExtensionHost>(details).ptr(); 1967 TrackTerminatedExtension(host->extension()); 1968 1969 // Unload the entire extension. We want it to be in a consistent state: 1970 // either fully working or not loaded at all, but never half-crashed. 1971 // We do it in a PostTask so that other handlers of this notification will 1972 // still have access to the Extension and ExtensionHost. 1973 MessageLoop::current()->PostTask(FROM_HERE, 1974 NewRunnableMethod(this, 1975 &ExtensionService::UnloadExtension, 1976 host->extension()->id(), 1977 UnloadedExtensionInfo::DISABLE)); 1978 break; 1979 } 1980 1981 case NotificationType::PREF_CHANGED: { 1982 std::string* pref_name = Details<std::string>(details).ptr(); 1983 if (*pref_name == prefs::kExtensionInstallAllowList || 1984 *pref_name == prefs::kExtensionInstallDenyList) { 1985 CheckAdminBlacklist(); 1986 } else { 1987 NOTREACHED() << "Unexpected preference name."; 1988 } 1989 break; 1990 } 1991 1992 default: 1993 NOTREACHED() << "Unexpected notification type."; 1994 } 1995 } 1996 1997 bool ExtensionService::HasApps() const { 1998 return !GetAppIds().empty(); 1999 } 2000 2001 ExtensionIdSet ExtensionService::GetAppIds() const { 2002 ExtensionIdSet result; 2003 for (ExtensionList::const_iterator it = extensions_.begin(); 2004 it != extensions_.end(); ++it) { 2005 if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT) 2006 result.insert((*it)->id()); 2007 } 2008 2009 return result; 2010 } 2011 2012 bool ExtensionService::IsBackgroundPageReady(const Extension* extension) { 2013 return (extension->background_url().is_empty() || 2014 extension_runtime_data_[extension->id()].background_page_ready); 2015 } 2016 2017 void ExtensionService::SetBackgroundPageReady(const Extension* extension) { 2018 DCHECK(!extension->background_url().is_empty()); 2019 extension_runtime_data_[extension->id()].background_page_ready = true; 2020 NotificationService::current()->Notify( 2021 NotificationType::EXTENSION_BACKGROUND_PAGE_READY, 2022 Source<const Extension>(extension), 2023 NotificationService::NoDetails()); 2024 } 2025 2026 bool ExtensionService::IsBeingUpgraded(const Extension* extension) { 2027 return extension_runtime_data_[extension->id()].being_upgraded; 2028 } 2029 2030 void ExtensionService::SetBeingUpgraded(const Extension* extension, 2031 bool value) { 2032 extension_runtime_data_[extension->id()].being_upgraded = value; 2033 } 2034 2035 PropertyBag* ExtensionService::GetPropertyBag(const Extension* extension) { 2036 return &extension_runtime_data_[extension->id()].property_bag; 2037 } 2038 2039 void ExtensionService::RegisterNaClModule(const GURL& url, 2040 const std::string& mime_type) { 2041 NaClModuleInfo info; 2042 info.url = url; 2043 info.mime_type = mime_type; 2044 2045 DCHECK(FindNaClModule(url) == nacl_module_list_.end()); 2046 nacl_module_list_.push_front(info); 2047 } 2048 2049 void ExtensionService::UnregisterNaClModule(const GURL& url) { 2050 NaClModuleInfoList::iterator iter = FindNaClModule(url); 2051 DCHECK(iter != nacl_module_list_.end()); 2052 nacl_module_list_.erase(iter); 2053 } 2054 2055 void ExtensionService::UpdatePluginListWithNaClModules() { 2056 FilePath path; 2057 PathService::Get(chrome::FILE_NACL_PLUGIN, &path); 2058 2059 webkit::npapi::PluginList::Singleton()->UnregisterInternalPlugin(path); 2060 2061 const PepperPluginInfo* pepper_info = 2062 PepperPluginRegistry::GetInstance()->GetInfoForPlugin(path); 2063 webkit::npapi::WebPluginInfo info = pepper_info->ToWebPluginInfo(); 2064 2065 DCHECK(nacl_module_list_.size() <= 1); 2066 for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin(); 2067 iter != nacl_module_list_.end(); ++iter) { 2068 webkit::npapi::WebPluginMimeType mime_type_info; 2069 mime_type_info.mime_type = iter->mime_type; 2070 mime_type_info.additional_param_names.push_back(UTF8ToUTF16("nacl")); 2071 mime_type_info.additional_param_values.push_back( 2072 UTF8ToUTF16(iter->url.spec())); 2073 info.mime_types.push_back(mime_type_info); 2074 } 2075 2076 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); 2077 webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(info); 2078 } 2079 2080 ExtensionService::NaClModuleInfoList::iterator 2081 ExtensionService::FindNaClModule(const GURL& url) { 2082 for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin(); 2083 iter != nacl_module_list_.end(); ++iter) { 2084 if (iter->url == url) 2085 return iter; 2086 } 2087 return nacl_module_list_.end(); 2088 } 2089