extension_service.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 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/bind.h" 12#include "base/callback.h" 13#include "base/command_line.h" 14#include "base/file_util.h" 15#include "base/logging.h" 16#include "base/metrics/histogram.h" 17#include "base/path_service.h" 18#include "base/stl_util.h" 19#include "base/string_number_conversions.h" 20#include "base/string_util.h" 21#include "base/stringprintf.h" 22#include "base/threading/thread_restrictions.h" 23#include "base/time.h" 24#include "base/utf_string_conversions.h" 25#include "base/values.h" 26#include "base/version.h" 27#include "chrome/browser/accessibility/accessibility_extension_api.h" 28#include "chrome/browser/bookmarks/bookmark_extension_api.h" 29#include "chrome/browser/bookmarks/bookmark_model_factory.h" 30#include "chrome/browser/browser_process.h" 31#include "chrome/browser/chrome_plugin_service_filter.h" 32#include "chrome/browser/debugger/devtools_window.h" 33#include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h" 34#include "chrome/browser/extensions/api/cookies/cookies_api.h" 35#include "chrome/browser/extensions/api/declarative/rules_registry_service.h" 36#include "chrome/browser/extensions/api/extension_action/extension_actions_api.h" 37#include "chrome/browser/extensions/api/font_settings/font_settings_api.h" 38#include "chrome/browser/extensions/api/managed_mode/managed_mode_api.h" 39#include "chrome/browser/extensions/api/management/management_api.h" 40#include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.h" 41#include "chrome/browser/extensions/api/preference/preference_api.h" 42#include "chrome/browser/extensions/api/runtime/runtime_api.h" 43#include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h" 44#include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h" 45#include "chrome/browser/extensions/app_notification_manager.h" 46#include "chrome/browser/extensions/app_sync_data.h" 47#include "chrome/browser/extensions/bluetooth_event_router.h" 48#include "chrome/browser/extensions/browser_event_router.h" 49#include "chrome/browser/extensions/component_loader.h" 50#include "chrome/browser/extensions/crx_installer.h" 51#include "chrome/browser/extensions/data_deleter.h" 52#include "chrome/browser/extensions/extension_disabled_ui.h" 53#include "chrome/browser/extensions/extension_error_reporter.h" 54#include "chrome/browser/extensions/extension_error_ui.h" 55#include "chrome/browser/extensions/extension_host.h" 56#include "chrome/browser/extensions/extension_install_ui.h" 57#include "chrome/browser/extensions/extension_process_manager.h" 58#include "chrome/browser/extensions/extension_sorting.h" 59#include "chrome/browser/extensions/extension_special_storage_policy.h" 60#include "chrome/browser/extensions/extension_sync_data.h" 61#include "chrome/browser/extensions/extension_system.h" 62#include "chrome/browser/extensions/extension_web_ui.h" 63#include "chrome/browser/extensions/external_install_ui.h" 64#include "chrome/browser/extensions/external_provider_impl.h" 65#include "chrome/browser/extensions/external_provider_interface.h" 66#include "chrome/browser/extensions/installed_loader.h" 67#include "chrome/browser/extensions/lazy_background_task_queue.h" 68#include "chrome/browser/extensions/pending_extension_manager.h" 69#include "chrome/browser/extensions/permissions_updater.h" 70#include "chrome/browser/extensions/platform_app_launcher.h" 71#include "chrome/browser/extensions/settings/settings_frontend.h" 72#include "chrome/browser/extensions/shell_window_registry.h" 73#include "chrome/browser/extensions/unpacked_installer.h" 74#include "chrome/browser/extensions/updater/extension_updater.h" 75#include "chrome/browser/extensions/window_event_router.h" 76#include "chrome/browser/history/history_extension_api.h" 77#include "chrome/browser/net/chrome_url_request_context.h" 78#include "chrome/browser/prefs/pref_service.h" 79#include "chrome/browser/profiles/profile.h" 80#include "chrome/browser/profiles/profile_manager.h" 81#include "chrome/browser/search_engines/template_url_service.h" 82#include "chrome/browser/search_engines/template_url_service_factory.h" 83#include "chrome/browser/themes/theme_service.h" 84#include "chrome/browser/themes/theme_service_factory.h" 85#include "chrome/browser/ui/webui/chrome_url_data_manager.h" 86#include "chrome/browser/ui/webui/favicon_source.h" 87#include "chrome/browser/ui/webui/ntp/thumbnail_source.h" 88#include "chrome/browser/ui/webui/theme_source.h" 89#include "chrome/common/child_process_logging.h" 90#include "chrome/common/chrome_notification_types.h" 91#include "chrome/common/chrome_paths.h" 92#include "chrome/common/chrome_switches.h" 93#include "chrome/common/chrome_version_info.h" 94#include "chrome/common/extensions/extension.h" 95#include "chrome/common/extensions/extension_error_utils.h" 96#include "chrome/common/extensions/extension_file_util.h" 97#include "chrome/common/extensions/extension_manifest_constants.h" 98#include "chrome/common/extensions/extension_messages.h" 99#include "chrome/common/extensions/extension_resource.h" 100#include "chrome/common/extensions/features/feature.h" 101#include "chrome/common/extensions/feature_switch.h" 102#include "chrome/common/extensions/manifest.h" 103#include "chrome/common/pref_names.h" 104#include "chrome/common/url_constants.h" 105#include "content/public/browser/browser_thread.h" 106#include "content/public/browser/devtools_agent_host_registry.h" 107#include "content/public/browser/devtools_manager.h" 108#include "content/public/browser/notification_service.h" 109#include "content/public/browser/notification_types.h" 110#include "content/public/browser/plugin_service.h" 111#include "content/public/browser/render_process_host.h" 112#include "content/public/common/pepper_plugin_info.h" 113#include "googleurl/src/gurl.h" 114#include "grit/generated_resources.h" 115#include "net/base/registry_controlled_domains/registry_controlled_domain.h" 116#include "sync/api/sync_change.h" 117#include "sync/api/sync_error_factory.h" 118#include "webkit/database/database_tracker.h" 119#include "webkit/database/database_util.h" 120 121#if defined(OS_CHROMEOS) 122#include "chrome/browser/chromeos/cros/cros_library.h" 123#include "chrome/browser/chromeos/extensions/file_browser_event_router.h" 124#include "chrome/browser/chromeos/extensions/input_method_event_router.h" 125#include "chrome/browser/chromeos/extensions/media_player_event_router.h" 126#include "chrome/browser/chromeos/input_method/input_method_manager.h" 127#include "chrome/browser/extensions/api/input_ime/input_ime_api.h" 128#include "content/public/browser/storage_partition.h" 129#include "webkit/fileapi/file_system_context.h" 130#include "webkit/fileapi/file_system_mount_point_provider.h" 131#endif 132 133using content::BrowserContext; 134using content::BrowserThread; 135using content::DevToolsAgentHost; 136using content::DevToolsAgentHostRegistry; 137using content::PluginService; 138using extensions::CrxInstaller; 139using extensions::Extension; 140using extensions::ExtensionIdSet; 141using extensions::ExtensionInfo; 142using extensions::FeatureSwitch; 143using extensions::UnloadedExtensionInfo; 144using extensions::PermissionMessage; 145using extensions::PermissionMessages; 146using extensions::PermissionSet; 147 148namespace errors = extension_manifest_errors; 149 150namespace { 151 152// Histogram values for logging events related to externally installed 153// extensions. 154enum ExternalExtensionEvent { 155 EXTERNAL_EXTENSION_INSTALLED = 0, 156 EXTERNAL_EXTENSION_IGNORED, 157 EXTERNAL_EXTENSION_REENABLED, 158 EXTERNAL_EXTENSION_UNINSTALLED, 159 EXTERNAL_EXTENSION_BUCKET_BOUNDARY, 160}; 161 162#if defined(OS_LINUX) 163static const int kOmniboxIconPaddingLeft = 2; 164static const int kOmniboxIconPaddingRight = 2; 165#elif defined(OS_MACOSX) 166static const int kOmniboxIconPaddingLeft = 0; 167static const int kOmniboxIconPaddingRight = 2; 168#else 169static const int kOmniboxIconPaddingLeft = 0; 170static const int kOmniboxIconPaddingRight = 0; 171#endif 172 173// Prompt the user this many times before considering an extension acknowledged. 174static const int kMaxExtensionAcknowledgePromptCount = 3; 175 176// Wait this many seconds after an extensions becomes idle before updating it. 177static const int kUpdateIdleDelay = 5; 178 179const char* kNaClPluginMimeType = "application/x-nacl"; 180 181static bool IsSyncableExtension(const Extension& extension) { 182 return extension.GetSyncType() == Extension::SYNC_TYPE_EXTENSION; 183} 184 185static bool IsSyncableApp(const Extension& extension) { 186 return extension.GetSyncType() == Extension::SYNC_TYPE_APP; 187} 188 189} // namespace 190 191ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData() 192 : background_page_ready(false), 193 being_upgraded(false), 194 has_used_webrequest(false) { 195} 196 197ExtensionService::ExtensionRuntimeData::~ExtensionRuntimeData() { 198} 199 200ExtensionService::NaClModuleInfo::NaClModuleInfo() { 201} 202 203ExtensionService::NaClModuleInfo::~NaClModuleInfo() { 204} 205 206// ExtensionService. 207 208const char ExtensionService::kInstallDirectoryName[] = "Extensions"; 209 210const char ExtensionService::kLocalAppSettingsDirectoryName[] = 211 "Local App Settings"; 212const char ExtensionService::kLocalExtensionSettingsDirectoryName[] = 213 "Local Extension Settings"; 214const char ExtensionService::kSyncAppSettingsDirectoryName[] = 215 "Sync App Settings"; 216const char ExtensionService::kSyncExtensionSettingsDirectoryName[] = 217 "Sync Extension Settings"; 218const char ExtensionService::kStateStoreName[] = "Extension State"; 219 220void ExtensionService::CheckExternalUninstall(const std::string& id) { 221 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 222 223 // Check if the providers know about this extension. 224 extensions::ProviderCollection::const_iterator i; 225 for (i = external_extension_providers_.begin(); 226 i != external_extension_providers_.end(); ++i) { 227 DCHECK(i->get()->IsReady()); 228 if (i->get()->HasExtension(id)) 229 return; // Yup, known extension, don't uninstall. 230 } 231 232 // We get the list of external extensions to check from preferences. 233 // It is possible that an extension has preferences but is not loaded. 234 // For example, an extension that requires experimental permissions 235 // will not be loaded if the experimental command line flag is not used. 236 // In this case, do not uninstall. 237 if (!GetInstalledExtension(id)) { 238 // We can't call UninstallExtension with an unloaded/invalid 239 // extension ID. 240 LOG(WARNING) << "Attempted uninstallation of unloaded/invalid extension " 241 << "with id: " << id; 242 return; 243 } 244 UninstallExtension(id, true, NULL); 245} 246 247void ExtensionService::ClearProvidersForTesting() { 248 external_extension_providers_.clear(); 249} 250 251void ExtensionService::AddProviderForTesting( 252 extensions::ExternalProviderInterface* test_provider) { 253 CHECK(test_provider); 254 external_extension_providers_.push_back( 255 linked_ptr<extensions::ExternalProviderInterface>(test_provider)); 256} 257 258bool ExtensionService::OnExternalExtensionUpdateUrlFound( 259 const std::string& id, 260 const GURL& update_url, 261 Extension::Location location) { 262 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 263 CHECK(Extension::IdIsValid(id)); 264 265 const Extension* extension = GetExtensionById(id, true); 266 if (extension) { 267 // Already installed. Skip this install if the current location has 268 // higher priority than |location|. 269 Extension::Location current = extension->location(); 270 if (current == Extension::GetHigherPriorityLocation(current, location)) 271 return false; 272 // Otherwise, overwrite the current installation. 273 } 274 275 // Add |id| to the set of pending extensions. If it can not be added, 276 // then there is already a pending record from a higher-priority install 277 // source. In this case, signal that this extension will not be 278 // installed by returning false. 279 if (!pending_extension_manager()->AddFromExternalUpdateUrl( 280 id, update_url, location)) { 281 return false; 282 } 283 284 update_once_all_providers_are_ready_ = true; 285 return true; 286} 287 288const Extension* ExtensionService::GetInstalledApp(const GURL& url) const { 289 const Extension* extension = extensions_.GetExtensionOrAppByURL( 290 ExtensionURLInfo(url)); 291 return (extension && extension->is_app()) ? extension : NULL; 292} 293 294bool ExtensionService::IsInstalledApp(const GURL& url) const { 295 return !!GetInstalledApp(url); 296} 297 298const Extension* ExtensionService::GetIsolatedAppForRenderer( 299 int renderer_child_id) const { 300 std::set<std::string> extension_ids = 301 process_map_.GetExtensionsInProcess(renderer_child_id); 302 // All apps in one process share the same partition. 303 // It is only possible for the app to have isolated storage 304 // if there is only 1 app in the process. 305 if (extension_ids.size() != 1) 306 return NULL; 307 308 const extensions::Extension* extension = 309 extensions_.GetByID(*(extension_ids.begin())); 310 // We still need to check is_storage_isolated(), 311 // because it's common for there to be one extension in a process 312 // with is_storage_isolated() == false. 313 if (extension && extension->is_storage_isolated()) 314 return extension; 315 316 return NULL; 317} 318 319// static 320// This function is used to implement the command-line switch 321// --uninstall-extension, and to uninstall an extension via sync. The LOG 322// statements within this function are used to inform the user if the uninstall 323// cannot be done. 324bool ExtensionService::UninstallExtensionHelper( 325 ExtensionService* extensions_service, 326 const std::string& extension_id) { 327 // We can't call UninstallExtension with an invalid extension ID. 328 if (!extensions_service->GetInstalledExtension(extension_id)) { 329 LOG(WARNING) << "Attempted uninstallation of non-existent extension with " 330 << "id: " << extension_id; 331 return false; 332 } 333 334 // The following call to UninstallExtension will not allow an uninstall of a 335 // policy-controlled extension. 336 string16 error; 337 if (!extensions_service->UninstallExtension(extension_id, false, &error)) { 338 LOG(WARNING) << "Cannot uninstall extension with id " << extension_id 339 << ": " << error; 340 return false; 341 } 342 343 return true; 344} 345 346ExtensionService::ExtensionService(Profile* profile, 347 const CommandLine* command_line, 348 const FilePath& install_directory, 349 extensions::ExtensionPrefs* extension_prefs, 350 bool autoupdate_enabled, 351 bool extensions_enabled) 352 : profile_(profile), 353 system_(extensions::ExtensionSystem::Get(profile)), 354 extension_prefs_(extension_prefs), 355 settings_frontend_(extensions::SettingsFrontend::Create(profile)), 356 pending_extension_manager_(*ALLOW_THIS_IN_INITIALIZER_LIST(this)), 357 install_directory_(install_directory), 358 extensions_enabled_(extensions_enabled), 359 show_extensions_prompts_(true), 360 ready_(false), 361 toolbar_model_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), 362 menu_manager_(profile), 363 app_notification_manager_( 364 new extensions::AppNotificationManager(profile)), 365 event_routers_initialized_(false), 366 update_once_all_providers_are_ready_(false), 367 browser_terminating_(false), 368 app_sync_bundle_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), 369 extension_sync_bundle_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), 370 extension_warnings_(profile), 371 app_shortcut_manager_(profile) { 372 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 373 374 // Figure out if extension installation should be enabled. 375 if (command_line->HasSwitch(switches::kDisableExtensions) || 376 profile->GetPrefs()->GetBoolean(prefs::kDisableExtensions)) { 377 extensions_enabled_ = false; 378 } 379 380 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, 381 content::NotificationService::AllBrowserContextsAndSources()); 382 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, 383 content::NotificationService::AllBrowserContextsAndSources()); 384 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, 385 content::NotificationService::AllBrowserContextsAndSources()); 386 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 387 content::NotificationService::AllBrowserContextsAndSources()); 388 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, 389 content::NotificationService::AllBrowserContextsAndSources()); 390 pref_change_registrar_.Init(profile->GetPrefs()); 391 pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, this); 392 pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, this); 393 394 // Set up the ExtensionUpdater 395 if (autoupdate_enabled) { 396 int update_frequency = kDefaultUpdateFrequencySeconds; 397 if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) { 398 base::StringToInt(command_line->GetSwitchValueASCII( 399 switches::kExtensionsUpdateFrequency), 400 &update_frequency); 401 } 402 updater_.reset(new extensions::ExtensionUpdater(this, 403 extension_prefs, 404 profile->GetPrefs(), 405 profile, 406 update_frequency)); 407 } 408 409 component_loader_.reset( 410 new extensions::ComponentLoader(this, 411 profile->GetPrefs(), 412 g_browser_process->local_state())); 413 414 app_notification_manager_->Init(); 415 416 if (extensions_enabled_) { 417 if (!command_line->HasSwitch(switches::kImport) && 418 !command_line->HasSwitch(switches::kImportFromFile)) { 419 extensions::ExternalProviderImpl::CreateExternalProviders( 420 this, profile_, &external_extension_providers_); 421 } 422 } 423 424 // Use monochrome icons for Omnibox icons. 425 omnibox_popup_icon_manager_.set_monochrome(true); 426 omnibox_icon_manager_.set_monochrome(true); 427 omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft, 428 0, kOmniboxIconPaddingRight)); 429 430 // Set this as the ExtensionService for extension sorting to ensure it 431 // cause syncs if required. 432 extension_prefs_->extension_sorting()->SetExtensionService(this); 433 434#if defined(ENABLE_EXTENSIONS) 435 extension_action_storage_manager_.reset( 436 new extensions::ExtensionActionStorageManager(profile_)); 437#endif 438 439 // How long is the path to the Extensions directory? 440 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.ExtensionRootPathLength", 441 install_directory_.value().length(), 0, 500, 100); 442} 443 444const ExtensionSet* ExtensionService::extensions() const { 445 return &extensions_; 446} 447 448const ExtensionSet* ExtensionService::disabled_extensions() const { 449 return &disabled_extensions_; 450} 451 452const ExtensionSet* ExtensionService::terminated_extensions() const { 453 return &terminated_extensions_; 454} 455 456const ExtensionSet* ExtensionService::GenerateInstalledExtensionsSet() const { 457 ExtensionSet* installed_extensions = new ExtensionSet(); 458 installed_extensions->InsertAll(extensions_); 459 installed_extensions->InsertAll(disabled_extensions_); 460 installed_extensions->InsertAll(terminated_extensions_); 461 return installed_extensions; 462} 463 464const ExtensionSet* ExtensionService::GetWipedOutExtensions() const { 465 ExtensionSet* extension_set = new ExtensionSet(); 466 for (ExtensionSet::const_iterator iter = disabled_extensions_.begin(); 467 iter != disabled_extensions_.end(); ++iter) { 468 int disabled_reason = extension_prefs_->GetDisableReasons((*iter)->id()); 469 if ((disabled_reason & Extension::DISABLE_SIDELOAD_WIPEOUT) != 0) 470 extension_set->Insert(*iter); 471 } 472 return extension_set; 473} 474 475extensions::PendingExtensionManager* 476 ExtensionService::pending_extension_manager() { 477 return &pending_extension_manager_; 478} 479 480ExtensionService::~ExtensionService() { 481 // No need to unload extensions here because they are profile-scoped, and the 482 // profile is in the process of being deleted. 483 484 extensions::ProviderCollection::const_iterator i; 485 for (i = external_extension_providers_.begin(); 486 i != external_extension_providers_.end(); ++i) { 487 extensions::ExternalProviderInterface* provider = i->get(); 488 provider->ServiceShutdown(); 489 } 490} 491 492void ExtensionService::InitEventRoutersAfterImport() { 493 RegisterForImportFinished(); 494} 495 496void ExtensionService::RegisterForImportFinished() { 497 if (!registrar_.IsRegistered(this, chrome::NOTIFICATION_IMPORT_FINISHED, 498 content::Source<Profile>(profile_))) { 499 registrar_.Add(this, chrome::NOTIFICATION_IMPORT_FINISHED, 500 content::Source<Profile>(profile_)); 501 } 502} 503 504void ExtensionService::InitAfterImport() { 505 CheckForExternalUpdates(); 506 507 GarbageCollectExtensions(); 508 509 // Idempotent, so although there is a possible race if the import 510 // process finished sometime in the middle of ProfileImpl::InitExtensions, 511 // it cannot happen twice. 512 InitEventRouters(); 513} 514 515void ExtensionService::InitEventRouters() { 516 if (event_routers_initialized_) 517 return; 518 519#if defined(ENABLE_EXTENSIONS) 520 history_event_router_.reset(new HistoryExtensionEventRouter(profile_)); 521 browser_event_router_.reset(new extensions::BrowserEventRouter(profile_)); 522 window_event_router_.reset(new extensions::WindowEventRouter(profile_)); 523 preference_event_router_.reset( 524 new extensions::PreferenceEventRouter(profile_)); 525 bookmark_event_router_.reset(new BookmarkExtensionEventRouter( 526 BookmarkModelFactory::GetForProfile(profile_))); 527 cookies_event_router_.reset( 528 new extensions::ExtensionCookiesEventRouter(profile_)); 529 management_event_router_.reset(new ExtensionManagementEventRouter(profile_)); 530 web_navigation_event_router_.reset( 531 new extensions::WebNavigationEventRouter(profile_)); 532 font_settings_event_router_.reset( 533 new extensions::FontSettingsEventRouter(profile_)); 534 managed_mode_event_router_.reset( 535 new extensions::ExtensionManagedModeEventRouter(profile_)); 536 push_messaging_event_router_.reset( 537 new extensions::PushMessagingEventRouter(profile_)); 538 media_galleries_private_event_router_.reset( 539 new extensions::MediaGalleriesPrivateEventRouter(profile_)); 540 bluetooth_event_router_.reset( 541 new extensions::ExtensionBluetoothEventRouter(profile_)); 542 543#if defined(OS_CHROMEOS) 544 FileBrowserEventRouterFactory::GetForProfile( 545 profile_)->ObserveFileSystemEvents(); 546 547 input_method_event_router_.reset( 548 new chromeos::ExtensionInputMethodEventRouter); 549 550 ExtensionMediaPlayerEventRouter::GetInstance()->Init(profile_); 551 extensions::InputImeEventRouter::GetInstance()->Init(); 552#endif // defined(OS_CHROMEOS) 553#endif // defined(ENABLE_EXTENSIONS) 554 event_routers_initialized_ = true; 555} 556 557void ExtensionService::OnProfileSyncServiceShutdown() { 558 // TODO(akalin): Move this block to Shutdown() once 559 // http://crbug.com/153827 is fixed. 560 if (push_messaging_event_router_.get()) 561 push_messaging_event_router_->Shutdown(); 562} 563 564void ExtensionService::Shutdown() { 565 // Do nothing for now. 566} 567 568const Extension* ExtensionService::GetExtensionById( 569 const std::string& id, bool include_disabled) const { 570 int include_mask = INCLUDE_ENABLED; 571 if (include_disabled) 572 include_mask |= INCLUDE_DISABLED; 573 return GetExtensionByIdInternal(id, include_mask); 574} 575 576void ExtensionService::Init() { 577 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 578 579 DCHECK(!ready_); // Can't redo init. 580 DCHECK_EQ(extensions_.size(), 0u); 581 582 // TODO(mek): It might be cleaner to do the FinishIdleInstallInfo stuff here 583 // instead of in installedloader 584 component_loader_->LoadAll(); 585 extensions::InstalledLoader(this).LoadAllExtensions(); 586 587 // The Sideload Wipeout effort takes place during load (see above), so once 588 // that is done the flag can be set so that we don't have to check again. 589 if (FeatureSwitch::sideload_wipeout()->IsEnabled()) 590 extension_prefs_->SetSideloadWipeoutDone(); 591 592 // If we are running in the import process, don't bother initializing the 593 // extension service since this can interfere with the main browser process 594 // that is already running an extension service for this profile. 595 // TODO(aa): can we start up even less of ExtensionService? 596 // http://crbug.com/107636 597 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kImport) && 598 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kImportFromFile)) { 599 if (g_browser_process->profile_manager() && 600 g_browser_process->profile_manager()->will_import()) { 601 RegisterForImportFinished(); 602 } else { 603 // TODO(erikkay) this should probably be deferred to a future point 604 // rather than running immediately at startup. 605 CheckForExternalUpdates(); 606 607 // TODO(erikkay) this should probably be deferred as well. 608 GarbageCollectExtensions(); 609 } 610 } 611} 612 613bool ExtensionService::UpdateExtension(const std::string& id, 614 const FilePath& extension_path, 615 const GURL& download_url, 616 CrxInstaller** out_crx_installer) { 617 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 618 if (browser_terminating_) { 619 LOG(WARNING) << "Skipping UpdateExtension due to browser shutdown"; 620 // Leak the temp file at extension_path. We don't want to add to the disk 621 // I/O burden at shutdown, we can't rely on the I/O completing anyway, and 622 // the file is in the OS temp directory which should be cleaned up for us. 623 return false; 624 } 625 626 const extensions::PendingExtensionInfo* pending_extension_info = 627 pending_extension_manager()->GetById(id); 628 629 int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED; 630 const Extension* extension = 631 GetExtensionByIdInternal(id, include_mask); 632 if (!pending_extension_info && !extension) { 633 LOG(WARNING) << "Will not update extension " << id 634 << " because it is not installed or pending"; 635 // Delete extension_path since we're not creating a CrxInstaller 636 // that would do it for us. 637 if (!BrowserThread::PostTask( 638 BrowserThread::FILE, FROM_HERE, 639 base::Bind( 640 &extension_file_util::DeleteFile, extension_path, false))) 641 NOTREACHED(); 642 643 return false; 644 } 645 646 // We want a silent install only for non-pending extensions and 647 // pending extensions that have install_silently set. 648 ExtensionInstallPrompt* client = NULL; 649 if (pending_extension_info && !pending_extension_info->install_silently()) 650 client = ExtensionInstallUI::CreateInstallPromptWithProfile(profile_); 651 652 scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(this, client)); 653 installer->set_expected_id(id); 654 if (pending_extension_info) { 655 installer->set_install_source(pending_extension_info->install_source()); 656 if (pending_extension_info->install_silently()) 657 installer->set_allow_silent_install(true); 658 } else if (extension) { 659 installer->set_install_source(extension->location()); 660 } 661 // If the extension was installed from or has migrated to the webstore, or 662 // its auto-update URL is from the webstore, treat it as a webstore install. 663 // Note that we ignore some older extensions with blank auto-update URLs 664 // because we are mostly concerned with restrictions on NaCl extensions, 665 // which are newer. 666 int creation_flags = Extension::NO_FLAGS; 667 if ((extension && extension->from_webstore()) || 668 (extension && extension->UpdatesFromGallery()) || 669 (!extension && extension_urls::IsWebstoreUpdateUrl( 670 pending_extension_info->update_url()))) { 671 creation_flags |= Extension::FROM_WEBSTORE; 672 } 673 674 // Bookmark apps being updated is kind of a contradiction, but that's because 675 // we mark the default apps as bookmark apps, and they're hosted in the web 676 // store, thus they can get updated. See http://crbug.com/101605 for more 677 // details. 678 if (extension && extension->from_bookmark()) 679 creation_flags |= Extension::FROM_BOOKMARK; 680 681 if (extension && extension->was_installed_by_default()) 682 creation_flags |= Extension::WAS_INSTALLED_BY_DEFAULT; 683 684 installer->set_creation_flags(creation_flags); 685 686 installer->set_delete_source(true); 687 installer->set_download_url(download_url); 688 installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE); 689 installer->InstallCrx(extension_path); 690 691 if (out_crx_installer) 692 *out_crx_installer = installer; 693 694 return true; 695} 696 697void ExtensionService::ReloadExtension(const std::string& extension_id) { 698 int events = HasShellWindows(extension_id) ? EVENT_LAUNCHED : EVENT_NONE; 699 ReloadExtensionWithEvents(extension_id, events); 700} 701 702void ExtensionService::RestartExtension(const std::string& extension_id) { 703 int events = HasShellWindows(extension_id) ? EVENT_RESTARTED : EVENT_NONE; 704 ReloadExtensionWithEvents(extension_id, events); 705} 706 707void ExtensionService::ReloadExtensionWithEvents( 708 const std::string& extension_id, 709 int events) { 710 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 711 FilePath path; 712 const Extension* current_extension = GetExtensionById(extension_id, false); 713 714 // Disable the extension if it's loaded. It might not be loaded if it crashed. 715 if (current_extension) { 716 // If the extension has an inspector open for its background page, detach 717 // the inspector and hang onto a cookie for it, so that we can reattach 718 // later. 719 // TODO(yoz): this is not incognito-safe! 720 ExtensionProcessManager* manager = system_->process_manager(); 721 extensions::ExtensionHost* host = 722 manager->GetBackgroundHostForExtension(extension_id); 723 if (host && DevToolsAgentHostRegistry::HasDevToolsAgentHost( 724 host->render_view_host())) { 725 // Look for an open inspector for the background page. 726 DevToolsAgentHost* agent = 727 DevToolsAgentHostRegistry::GetDevToolsAgentHost( 728 host->render_view_host()); 729 int devtools_cookie = 730 content::DevToolsManager::GetInstance()->DetachClientHost(agent); 731 if (devtools_cookie >= 0) 732 orphaned_dev_tools_[extension_id] = devtools_cookie; 733 } 734 735 on_load_events_[extension_id] = events; 736 737 path = current_extension->path(); 738 DisableExtension(extension_id, Extension::DISABLE_RELOAD); 739 disabled_extension_paths_[extension_id] = path; 740 } else { 741 path = unloaded_extension_paths_[extension_id]; 742 } 743 744 if (pending_extension_updates_.Contains(extension_id)) { 745 FinishInstallation(extension_id); 746 return; 747 } 748 749 // If we're reloading a component extension, use the component extension 750 // loader's reloader. 751 if (component_loader_->Exists(extension_id)) { 752 component_loader_->Reload(extension_id); 753 return; 754 } 755 756 // Check the installed extensions to see if what we're reloading was already 757 // installed. 758 scoped_ptr<ExtensionInfo> installed_extension( 759 extension_prefs_->GetInstalledExtensionInfo(extension_id)); 760 if (installed_extension.get() && 761 installed_extension->extension_manifest.get()) { 762 extensions::InstalledLoader(this).Load(*installed_extension, false); 763 } else { 764 // Otherwise, the extension is unpacked (location LOAD). 765 // We should always be able to remember the extension's path. If it's not in 766 // the map, someone failed to update |unloaded_extension_paths_|. 767 CHECK(!path.empty()); 768 extensions::UnpackedInstaller::Create(this)->Load(path); 769 } 770} 771 772bool ExtensionService::UninstallExtension( 773 std::string extension_id, 774 bool external_uninstall, 775 string16* error) { 776 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 777 778 scoped_refptr<const Extension> extension(GetInstalledExtension(extension_id)); 779 780 // Callers should not send us nonexistent extensions. 781 CHECK(extension); 782 783 // Policy change which triggers an uninstall will always set 784 // |external_uninstall| to true so this is the only way to uninstall 785 // managed extensions. 786 if (!external_uninstall && 787 !system_->management_policy()->UserMayModifySettings( 788 extension.get(), error)) { 789 content::NotificationService::current()->Notify( 790 chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED, 791 content::Source<Profile>(profile_), 792 content::Details<const Extension>(extension)); 793 return false; 794 } 795 796 // Extract the data we need for sync now, but don't actually sync until we've 797 // completed the uninstallation. 798 syncer::SyncChange sync_change; 799 if (app_sync_bundle_.HandlesApp(*extension)) { 800 sync_change = app_sync_bundle_.CreateSyncChangeToDelete(extension); 801 } else if (extension_sync_bundle_.HandlesExtension(*extension)) { 802 sync_change = extension_sync_bundle_.CreateSyncChangeToDelete(extension); 803 } 804 805 if (IsUnacknowledgedExternalExtension(extension)) { 806 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent", 807 EXTERNAL_EXTENSION_UNINSTALLED, 808 EXTERNAL_EXTENSION_BUCKET_BOUNDARY); 809 } 810 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType", 811 extension->GetType(), 100); 812 RecordPermissionMessagesHistogram( 813 extension, "Extensions.Permissions_Uninstall"); 814 815 TemplateURLService* url_service = 816 TemplateURLServiceFactory::GetForProfile(profile_); 817 if (url_service) 818 url_service->UnregisterExtensionKeyword(extension); 819 820 // Unload before doing more cleanup to ensure that nothing is hanging on to 821 // any of these resources. 822 UnloadExtension(extension_id, extension_misc::UNLOAD_REASON_UNINSTALL); 823 824 extension_prefs_->OnExtensionUninstalled(extension_id, extension->location(), 825 external_uninstall); 826 827 // Tell the backend to start deleting installed extensions on the file thread. 828 if (Extension::LOAD != extension->location()) { 829 if (!BrowserThread::PostTask( 830 BrowserThread::FILE, FROM_HERE, 831 base::Bind( 832 &extension_file_util::UninstallExtension, 833 install_directory_, 834 extension_id))) 835 NOTREACHED(); 836 } 837 838 GURL launch_web_url_origin(extension->launch_web_url()); 839 launch_web_url_origin = launch_web_url_origin.GetOrigin(); 840 bool is_storage_isolated = extension->is_storage_isolated(); 841 842 if (extension->is_hosted_app() && 843 !profile_->GetExtensionSpecialStoragePolicy()-> 844 IsStorageProtected(launch_web_url_origin)) { 845 extensions::DataDeleter::StartDeleting( 846 profile_, extension_id, launch_web_url_origin, is_storage_isolated); 847 } 848 extensions::DataDeleter::StartDeleting( 849 profile_, extension_id, extension->url(), is_storage_isolated); 850 851 UntrackTerminatedExtension(extension_id); 852 853 // Notify interested parties that we've uninstalled this extension. 854 content::NotificationService::current()->Notify( 855 chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 856 content::Source<Profile>(profile_), 857 content::Details<const Extension>(extension)); 858 859 if (app_sync_bundle_.HasExtensionId(extension_id) && 860 sync_change.sync_data().GetDataType() == syncer::APPS) { 861 app_sync_bundle_.ProcessDeletion(extension_id, sync_change); 862 } else if (extension_sync_bundle_.HasExtensionId(extension_id) && 863 sync_change.sync_data().GetDataType() == syncer::EXTENSIONS) { 864 extension_sync_bundle_.ProcessDeletion(extension_id, sync_change); 865 } 866 867 pending_extension_updates_.Remove(extension_id); 868 869 // Track the uninstallation. 870 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionUninstalled", 1, 2); 871 872 // Uninstalling one extension might have solved the problems of others. 873 // Therefore, we clear warnings of this type for all extensions. 874 std::set<ExtensionWarningSet::WarningType> warnings; 875 extension_warnings_.GetWarningsAffectingExtension(extension_id, &warnings); 876 extension_warnings_.ClearWarnings(warnings); 877 878 return true; 879} 880 881bool ExtensionService::IsExtensionEnabled( 882 const std::string& extension_id) const { 883 if (extensions_.Contains(extension_id) || 884 terminated_extensions_.Contains(extension_id)) { 885 return true; 886 } 887 888 if (disabled_extensions_.Contains(extension_id)) 889 return false; 890 891 // If the extension hasn't been loaded yet, check the prefs for it. Assume 892 // enabled unless otherwise noted. 893 return !extension_prefs_->IsExtensionDisabled(extension_id) && 894 !extension_prefs_->IsExternalExtensionUninstalled(extension_id); 895} 896 897bool ExtensionService::IsExternalExtensionUninstalled( 898 const std::string& extension_id) const { 899 return extension_prefs_->IsExternalExtensionUninstalled(extension_id); 900} 901 902void ExtensionService::EnableExtension(const std::string& extension_id) { 903 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 904 905 if (IsExtensionEnabled(extension_id)) 906 return; 907 908 extension_prefs_->SetExtensionState(extension_id, Extension::ENABLED); 909 extension_prefs_->ClearDisableReasons(extension_id); 910 911 const Extension* extension = GetExtensionByIdInternal(extension_id, 912 INCLUDE_DISABLED); 913 // This can happen if sync enables an extension that is not 914 // installed yet. 915 if (!extension) 916 return; 917 918 if (IsUnacknowledgedExternalExtension(extension)) { 919 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent", 920 EXTERNAL_EXTENSION_REENABLED, 921 EXTERNAL_EXTENSION_BUCKET_BOUNDARY); 922 AcknowledgeExternalExtension(extension->id()); 923 } 924 925 // Move it over to the enabled list. 926 extensions_.Insert(make_scoped_refptr(extension)); 927 disabled_extensions_.Remove(extension->id()); 928 929 NotifyExtensionLoaded(extension); 930 931 // Notify listeners that the extension was enabled. 932 content::NotificationService::current()->Notify( 933 chrome::NOTIFICATION_EXTENSION_ENABLED, 934 content::Source<Profile>(profile_), 935 content::Details<const Extension>(extension)); 936 937 SyncExtensionChangeIfNeeded(*extension); 938} 939 940void ExtensionService::DisableExtension( 941 const std::string& extension_id, 942 Extension::DisableReason disable_reason) { 943 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 944 945 // The extension may have been disabled already. 946 if (!IsExtensionEnabled(extension_id)) 947 return; 948 949 const Extension* extension = GetInstalledExtension(extension_id); 950 // |extension| can be NULL if sync disables an extension that is not 951 // installed yet. 952 if (extension && 953 !system_->management_policy()->UserMayModifySettings(extension, NULL)) { 954 return; 955 } 956 957 extension_prefs_->SetExtensionState(extension_id, Extension::DISABLED); 958 extension_prefs_->AddDisableReason(extension_id, disable_reason); 959 960 int include_mask = INCLUDE_ENABLED | INCLUDE_TERMINATED; 961 extension = GetExtensionByIdInternal(extension_id, include_mask); 962 if (!extension) 963 return; 964 965 // Move it over to the disabled list. Don't send a second unload notification 966 // for terminated extensions being disabled. 967 disabled_extensions_.Insert(make_scoped_refptr(extension)); 968 if (extensions_.Contains(extension->id())) { 969 extensions_.Remove(extension->id()); 970 NotifyExtensionUnloaded(extension, extension_misc::UNLOAD_REASON_DISABLE); 971 } else { 972 terminated_extensions_.Remove(extension->id()); 973 } 974 975 SyncExtensionChangeIfNeeded(*extension); 976 977 // Deactivating one extension might have solved the problems of others. 978 // Therefore, we clear warnings of this type for all extensions. 979 std::set<ExtensionWarningSet::WarningType> warnings; 980 extension_warnings_.GetWarningsAffectingExtension(extension_id, &warnings); 981 extension_warnings_.ClearWarnings(warnings); 982} 983 984void ExtensionService::GrantPermissionsAndEnableExtension( 985 const Extension* extension, bool record_oauth2_grant) { 986 GrantPermissions(extension, record_oauth2_grant); 987 RecordPermissionMessagesHistogram( 988 extension, "Extensions.Permissions_ReEnable"); 989 extension_prefs_->SetDidExtensionEscalatePermissions(extension, false); 990 EnableExtension(extension->id()); 991} 992 993void ExtensionService::GrantPermissions(const Extension* extension, 994 bool record_oauth2_grant) { 995 CHECK(extension); 996 extensions::PermissionsUpdater perms_updater(profile()); 997 perms_updater.GrantActivePermissions(extension, record_oauth2_grant); 998} 999 1000// static 1001void ExtensionService::RecordPermissionMessagesHistogram( 1002 const Extension* e, const char* histogram) { 1003 // Since this is called from multiple sources, and since the Histogram macros 1004 // use statics, we need to manually lookup the Histogram ourselves. 1005 base::Histogram* counter = base::LinearHistogram::FactoryGet( 1006 histogram, 1007 1, 1008 PermissionMessage::kEnumBoundary, 1009 PermissionMessage::kEnumBoundary + 1, 1010 base::Histogram::kUmaTargetedHistogramFlag); 1011 1012 PermissionMessages permissions = e->GetPermissionMessages(); 1013 if (permissions.empty()) { 1014 counter->Add(PermissionMessage::kNone); 1015 } else { 1016 for (PermissionMessages::iterator it = permissions.begin(); 1017 it != permissions.end(); ++it) 1018 counter->Add(it->id()); 1019 } 1020} 1021 1022void ExtensionService::NotifyExtensionLoaded(const Extension* extension) { 1023 // The ChromeURLRequestContexts need to be first to know that the extension 1024 // was loaded, otherwise a race can arise where a renderer that is created 1025 // for the extension may try to load an extension URL with an extension id 1026 // that the request context doesn't yet know about. The profile is responsible 1027 // for ensuring its URLRequestContexts appropriately discover the loaded 1028 // extension. 1029 system_->RegisterExtensionWithRequestContexts(extension); 1030 1031 // Tell renderers about the new extension, unless it's a theme (renderers 1032 // don't need to know about themes). 1033 if (!extension->is_theme()) { 1034 for (content::RenderProcessHost::iterator i( 1035 content::RenderProcessHost::AllHostsIterator()); 1036 !i.IsAtEnd(); i.Advance()) { 1037 content::RenderProcessHost* host = i.GetCurrentValue(); 1038 Profile* host_profile = 1039 Profile::FromBrowserContext(host->GetBrowserContext()); 1040 if (host_profile->GetOriginalProfile() == 1041 profile_->GetOriginalProfile()) { 1042 std::vector<ExtensionMsg_Loaded_Params> loaded_extensions( 1043 1, ExtensionMsg_Loaded_Params(extension)); 1044 host->Send( 1045 new ExtensionMsg_Loaded(loaded_extensions)); 1046 } 1047 } 1048 } 1049 1050 // Tell subsystems that use the EXTENSION_LOADED notification about the new 1051 // extension. 1052 // 1053 // NOTE: It is important that this happen after notifying the renderers about 1054 // the new extensions so that if we navigate to an extension URL in 1055 // NOTIFICATION_EXTENSION_LOADED, the renderer is guaranteed to know about it. 1056 content::NotificationService::current()->Notify( 1057 chrome::NOTIFICATION_EXTENSION_LOADED, 1058 content::Source<Profile>(profile_), 1059 content::Details<const Extension>(extension)); 1060 1061 // Tell a random-ass collection of other subsystems about the new extension. 1062 // TODO(aa): What should we do with all this goop? Can it move into the 1063 // relevant objects via EXTENSION_LOADED? 1064 1065 profile_->GetExtensionSpecialStoragePolicy()-> 1066 GrantRightsForExtension(extension); 1067 1068 UpdateActiveExtensionsInCrashReporter(); 1069 1070 ExtensionWebUI::RegisterChromeURLOverrides( 1071 profile_, extension->GetChromeURLOverrides()); 1072 1073 TemplateURLService* url_service = 1074 TemplateURLServiceFactory::GetForProfile(profile_); 1075 if (url_service) 1076 url_service->RegisterExtensionKeyword(extension); 1077 1078 // Load the icon for omnibox-enabled extensions so it will be ready to display 1079 // in the URL bar. 1080 if (!extension->omnibox_keyword().empty()) { 1081 omnibox_popup_icon_manager_.LoadIcon(extension); 1082 omnibox_icon_manager_.LoadIcon(extension); 1083 } 1084 1085 // If the extension has permission to load chrome://favicon/ resources we need 1086 // to make sure that the FaviconSource is registered with the 1087 // ChromeURLDataManager. 1088 if (extension->HasHostPermission(GURL(chrome::kChromeUIFaviconURL))) { 1089 FaviconSource* favicon_source = new FaviconSource(profile_, 1090 FaviconSource::FAVICON); 1091 ChromeURLDataManager::AddDataSource(profile_, favicon_source); 1092 } 1093 1094#if !defined(OS_ANDROID) 1095 // Same for chrome://theme/ resources. 1096 if (extension->HasHostPermission(GURL(chrome::kChromeUIThemeURL))) { 1097 ThemeSource* theme_source = new ThemeSource(profile_); 1098 ChromeURLDataManager::AddDataSource(profile_, theme_source); 1099 } 1100#endif 1101 1102 // Same for chrome://thumb/ resources. 1103 if (extension->HasHostPermission(GURL(chrome::kChromeUIThumbnailURL))) { 1104 ThumbnailSource* thumbnail_source = new ThumbnailSource(profile_); 1105 ChromeURLDataManagerFactory::GetForProfile(profile_)-> 1106 AddDataSource(thumbnail_source); 1107 } 1108 1109 // TODO(mpcomplete): This ends up affecting all profiles. See crbug.com/80757. 1110 bool plugins_changed = false; 1111 for (size_t i = 0; i < extension->plugins().size(); ++i) { 1112 const Extension::PluginInfo& plugin = extension->plugins()[i]; 1113 PluginService::GetInstance()->RefreshPlugins(); 1114 PluginService::GetInstance()->AddExtraPluginPath(plugin.path); 1115 plugins_changed = true; 1116 ChromePluginServiceFilter* filter = 1117 ChromePluginServiceFilter::GetInstance(); 1118 if (plugin.is_public) { 1119 filter->RestrictPluginToProfileAndOrigin( 1120 plugin.path, profile_, GURL()); 1121 } else { 1122 filter->RestrictPluginToProfileAndOrigin( 1123 plugin.path, profile_, extension->url()); 1124 } 1125 } 1126 1127 bool nacl_modules_changed = false; 1128 for (size_t i = 0; i < extension->nacl_modules().size(); ++i) { 1129 const Extension::NaClModuleInfo& module = extension->nacl_modules()[i]; 1130 RegisterNaClModule(module.url, module.mime_type); 1131 nacl_modules_changed = true; 1132 } 1133 1134 if (nacl_modules_changed) 1135 UpdatePluginListWithNaClModules(); 1136 1137 if (plugins_changed || nacl_modules_changed) 1138 PluginService::GetInstance()->PurgePluginListCache(profile_, false); 1139 1140#if defined(OS_CHROMEOS) 1141 for (std::vector<Extension::InputComponentInfo>::const_iterator component = 1142 extension->input_components().begin(); 1143 component != extension->input_components().end(); 1144 ++component) { 1145 if (component->type == Extension::INPUT_COMPONENT_TYPE_IME) { 1146 extensions::InputImeEventRouter::GetInstance()->RegisterIme( 1147 profile_, extension->id(), *component); 1148 } 1149 } 1150#endif 1151} 1152 1153void ExtensionService::NotifyExtensionUnloaded( 1154 const Extension* extension, 1155 extension_misc::UnloadedExtensionReason reason) { 1156 UnloadedExtensionInfo details(extension, reason); 1157 content::NotificationService::current()->Notify( 1158 chrome::NOTIFICATION_EXTENSION_UNLOADED, 1159 content::Source<Profile>(profile_), 1160 content::Details<UnloadedExtensionInfo>(&details)); 1161 1162 for (content::RenderProcessHost::iterator i( 1163 content::RenderProcessHost::AllHostsIterator()); 1164 !i.IsAtEnd(); i.Advance()) { 1165 content::RenderProcessHost* host = i.GetCurrentValue(); 1166 Profile* host_profile = 1167 Profile::FromBrowserContext(host->GetBrowserContext()); 1168 if (host_profile->GetOriginalProfile() == profile_->GetOriginalProfile()) 1169 host->Send(new ExtensionMsg_Unloaded(extension->id())); 1170 } 1171 1172 system_->UnregisterExtensionWithRequestContexts(extension->id(), reason); 1173 profile_->GetExtensionSpecialStoragePolicy()-> 1174 RevokeRightsForExtension(extension); 1175 1176 ExtensionWebUI::UnregisterChromeURLOverrides( 1177 profile_, extension->GetChromeURLOverrides()); 1178 1179#if defined(OS_CHROMEOS) 1180 // Revoke external file access to third party extensions. 1181 fileapi::FileSystemContext* filesystem_context = 1182 BrowserContext::GetDefaultStoragePartition(profile_)-> 1183 GetFileSystemContext(); 1184 if (filesystem_context && filesystem_context->external_provider()) { 1185 filesystem_context->external_provider()-> 1186 RevokeAccessForExtension(extension->id()); 1187 } 1188 1189 if (extension->input_components().size() > 0) { 1190 extensions::InputImeEventRouter::GetInstance()->UnregisterAllImes( 1191 profile_, extension->id()); 1192 } 1193#endif 1194 1195 UpdateActiveExtensionsInCrashReporter(); 1196 1197 bool plugins_changed = false; 1198 for (size_t i = 0; i < extension->plugins().size(); ++i) { 1199 const Extension::PluginInfo& plugin = extension->plugins()[i]; 1200 PluginService::GetInstance()->ForcePluginShutdown(plugin.path); 1201 PluginService::GetInstance()->RefreshPlugins(); 1202 PluginService::GetInstance()->RemoveExtraPluginPath(plugin.path); 1203 plugins_changed = true; 1204 ChromePluginServiceFilter::GetInstance()->UnrestrictPlugin(plugin.path); 1205 } 1206 1207 bool nacl_modules_changed = false; 1208 for (size_t i = 0; i < extension->nacl_modules().size(); ++i) { 1209 const Extension::NaClModuleInfo& module = extension->nacl_modules()[i]; 1210 UnregisterNaClModule(module.url); 1211 nacl_modules_changed = true; 1212 } 1213 1214 if (nacl_modules_changed) 1215 UpdatePluginListWithNaClModules(); 1216 1217 if (plugins_changed || nacl_modules_changed) 1218 PluginService::GetInstance()->PurgePluginListCache(profile_, false); 1219} 1220 1221void ExtensionService::UpdateExtensionBlacklist( 1222 const std::vector<std::string>& blacklist) { 1223 // Use this set to indicate if an extension in the blacklist has been used. 1224 std::set<std::string> blacklist_set; 1225 for (unsigned int i = 0; i < blacklist.size(); ++i) { 1226 if (Extension::IdIsValid(blacklist[i])) 1227 blacklist_set.insert(blacklist[i]); 1228 } 1229 extension_prefs_->UpdateBlacklist(blacklist_set); 1230 CheckManagementPolicy(); 1231} 1232 1233Profile* ExtensionService::profile() { 1234 return profile_; 1235} 1236 1237extensions::ExtensionPrefs* ExtensionService::extension_prefs() { 1238 return extension_prefs_; 1239} 1240 1241extensions::SettingsFrontend* ExtensionService::settings_frontend() { 1242 return settings_frontend_.get(); 1243} 1244 1245extensions::ContentSettingsStore* ExtensionService::GetContentSettingsStore() { 1246 return extension_prefs()->content_settings_store(); 1247} 1248 1249bool ExtensionService::is_ready() { 1250 return ready_; 1251} 1252 1253extensions::ExtensionUpdater* ExtensionService::updater() { 1254 return updater_.get(); 1255} 1256 1257void ExtensionService::CheckManagementPolicy() { 1258 std::vector<std::string> to_be_removed; 1259 // Loop through extensions list, unload installed extensions. 1260 for (ExtensionSet::const_iterator iter = extensions_.begin(); 1261 iter != extensions_.end(); ++iter) { 1262 const Extension* extension = (*iter); 1263 if (!system_->management_policy()->UserMayLoad(extension, NULL)) 1264 to_be_removed.push_back(extension->id()); 1265 } 1266 1267 // UnloadExtension will change the extensions_ list. So, we should 1268 // call it outside the iterator loop. 1269 for (size_t i = 0; i < to_be_removed.size(); ++i) 1270 UnloadExtension(to_be_removed[i], extension_misc::UNLOAD_REASON_DISABLE); 1271} 1272 1273void ExtensionService::CheckForUpdatesSoon() { 1274 if (updater()) { 1275 if (AreAllExternalProvidersReady()) { 1276 updater()->CheckSoon(); 1277 } else { 1278 // Sync can start updating before all the external providers are ready 1279 // during startup. Start the update as soon as those providers are ready, 1280 // but not before. 1281 update_once_all_providers_are_ready_ = true; 1282 } 1283 } else { 1284 LOG(WARNING) << "CheckForUpdatesSoon() called with auto-update turned off"; 1285 } 1286} 1287 1288syncer::SyncError ExtensionService::MergeDataAndStartSyncing( 1289 syncer::ModelType type, 1290 const syncer::SyncDataList& initial_sync_data, 1291 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 1292 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { 1293 CHECK(sync_processor.get()); 1294 CHECK(sync_error_factory.get()); 1295 1296 switch (type) { 1297 case syncer::EXTENSIONS: 1298 extension_sync_bundle_.SetupSync(sync_processor.release(), 1299 sync_error_factory.release(), 1300 initial_sync_data); 1301 break; 1302 1303 case syncer::APPS: 1304 app_sync_bundle_.SetupSync(sync_processor.release(), 1305 sync_error_factory.release(), 1306 initial_sync_data); 1307 break; 1308 1309 default: 1310 LOG(FATAL) << "Got " << type << " ModelType"; 1311 } 1312 1313 // Process local extensions. 1314 // TODO(yoz): Determine whether pending extensions should be considered too. 1315 // See crbug.com/104399. 1316 syncer::SyncDataList sync_data_list = GetAllSyncData(type); 1317 syncer::SyncChangeList sync_change_list; 1318 for (syncer::SyncDataList::const_iterator i = sync_data_list.begin(); 1319 i != sync_data_list.end(); 1320 ++i) { 1321 switch (type) { 1322 case syncer::EXTENSIONS: 1323 sync_change_list.push_back( 1324 extension_sync_bundle_.CreateSyncChange(*i)); 1325 break; 1326 case syncer::APPS: 1327 sync_change_list.push_back(app_sync_bundle_.CreateSyncChange(*i)); 1328 break; 1329 default: 1330 LOG(FATAL) << "Got " << type << " ModelType"; 1331 } 1332 } 1333 1334 1335 if (type == syncer::EXTENSIONS) { 1336 extension_sync_bundle_.ProcessSyncChangeList(sync_change_list); 1337 } else if (type == syncer::APPS) { 1338 app_sync_bundle_.ProcessSyncChangeList(sync_change_list); 1339 } 1340 1341 return syncer::SyncError(); 1342} 1343 1344void ExtensionService::StopSyncing(syncer::ModelType type) { 1345 if (type == syncer::APPS) { 1346 app_sync_bundle_.Reset(); 1347 } else if (type == syncer::EXTENSIONS) { 1348 extension_sync_bundle_.Reset(); 1349 } 1350} 1351 1352syncer::SyncDataList ExtensionService::GetAllSyncData( 1353 syncer::ModelType type) const { 1354 if (type == syncer::EXTENSIONS) 1355 return extension_sync_bundle_.GetAllSyncData(); 1356 if (type == syncer::APPS) 1357 return app_sync_bundle_.GetAllSyncData(); 1358 1359 // We should only get sync data for extensions and apps. 1360 NOTREACHED(); 1361 1362 return syncer::SyncDataList(); 1363} 1364 1365syncer::SyncError ExtensionService::ProcessSyncChanges( 1366 const tracked_objects::Location& from_here, 1367 const syncer::SyncChangeList& change_list) { 1368 for (syncer::SyncChangeList::const_iterator i = change_list.begin(); 1369 i != change_list.end(); 1370 ++i) { 1371 syncer::ModelType type = i->sync_data().GetDataType(); 1372 if (type == syncer::EXTENSIONS) { 1373 extension_sync_bundle_.ProcessSyncChange( 1374 extensions::ExtensionSyncData(*i)); 1375 } else if (type == syncer::APPS) { 1376 app_sync_bundle_.ProcessSyncChange(extensions::AppSyncData(*i)); 1377 } 1378 } 1379 1380 extension_prefs()->extension_sorting()->FixNTPOrdinalCollisions(); 1381 1382 return syncer::SyncError(); 1383} 1384 1385extensions::ExtensionSyncData ExtensionService::GetExtensionSyncData( 1386 const Extension& extension) const { 1387 return extensions::ExtensionSyncData(extension, 1388 IsExtensionEnabled(extension.id()), 1389 IsIncognitoEnabled(extension.id())); 1390} 1391 1392extensions::AppSyncData ExtensionService::GetAppSyncData( 1393 const Extension& extension) const { 1394 return extensions::AppSyncData( 1395 extension, 1396 IsExtensionEnabled(extension.id()), 1397 IsIncognitoEnabled(extension.id()), 1398 extension_prefs_->GetAppNotificationClientId(extension.id()), 1399 extension_prefs_->IsAppNotificationDisabled(extension.id()), 1400 extension_prefs_->extension_sorting()->GetAppLaunchOrdinal( 1401 extension.id()), 1402 extension_prefs_->extension_sorting()->GetPageOrdinal(extension.id())); 1403} 1404 1405std::vector<extensions::ExtensionSyncData> 1406 ExtensionService::GetExtensionSyncDataList() const { 1407 std::vector<extensions::ExtensionSyncData> extension_sync_list; 1408 extension_sync_bundle_.GetExtensionSyncDataListHelper(extensions_, 1409 &extension_sync_list); 1410 extension_sync_bundle_.GetExtensionSyncDataListHelper(disabled_extensions_, 1411 &extension_sync_list); 1412 extension_sync_bundle_.GetExtensionSyncDataListHelper(terminated_extensions_, 1413 &extension_sync_list); 1414 1415 std::vector<extensions::ExtensionSyncData> pending_extensions = 1416 extension_sync_bundle_.GetPendingData(); 1417 extension_sync_list.insert(extension_sync_list.begin(), 1418 pending_extensions.begin(), 1419 pending_extensions.end()); 1420 1421 return extension_sync_list; 1422} 1423 1424std::vector<extensions::AppSyncData> ExtensionService::GetAppSyncDataList() 1425 const { 1426 std::vector<extensions::AppSyncData> app_sync_list; 1427 app_sync_bundle_.GetAppSyncDataListHelper(extensions_, &app_sync_list); 1428 app_sync_bundle_.GetAppSyncDataListHelper(disabled_extensions_, 1429 &app_sync_list); 1430 app_sync_bundle_.GetAppSyncDataListHelper(terminated_extensions_, 1431 &app_sync_list); 1432 1433 std::vector<extensions::AppSyncData> pending_apps = 1434 app_sync_bundle_.GetPendingData(); 1435 app_sync_list.insert(app_sync_list.begin(), 1436 pending_apps.begin(), 1437 pending_apps.end()); 1438 1439 return app_sync_list; 1440} 1441 1442bool ExtensionService::ProcessExtensionSyncData( 1443 const extensions::ExtensionSyncData& extension_sync_data) { 1444 if (!ProcessExtensionSyncDataHelper(extension_sync_data, 1445 syncer::EXTENSIONS)) { 1446 extension_sync_bundle_.AddPendingExtension(extension_sync_data.id(), 1447 extension_sync_data); 1448 CheckForUpdatesSoon(); 1449 return false; 1450 } 1451 1452 return true; 1453} 1454 1455bool ExtensionService::ProcessAppSyncData( 1456 const extensions::AppSyncData& app_sync_data) { 1457 const std::string& id = app_sync_data.id(); 1458 const Extension* extension = GetInstalledExtension(id); 1459 bool extension_installed = (extension != NULL); 1460 1461 if (app_sync_data.app_launch_ordinal().IsValid() && 1462 app_sync_data.page_ordinal().IsValid()) { 1463 extension_prefs_->extension_sorting()->SetAppLaunchOrdinal( 1464 id, 1465 app_sync_data.app_launch_ordinal()); 1466 extension_prefs_->extension_sorting()->SetPageOrdinal( 1467 id, 1468 app_sync_data.page_ordinal()); 1469 } 1470 1471 if (extension_installed) { 1472 if (app_sync_data.notifications_disabled() != 1473 extension_prefs_->IsAppNotificationDisabled(id)) { 1474 extension_prefs_->SetAppNotificationDisabled( 1475 id, app_sync_data.notifications_disabled()); 1476 } 1477 } 1478 1479 if (!ProcessExtensionSyncDataHelper(app_sync_data.extension_sync_data(), 1480 syncer::APPS)) { 1481 app_sync_bundle_.AddPendingApp(id, app_sync_data); 1482 CheckForUpdatesSoon(); 1483 return false; 1484 } 1485 1486 return true; 1487} 1488 1489bool ExtensionService::IsCorrectSyncType(const Extension& extension, 1490 syncer::ModelType type) const { 1491 if (type == syncer::EXTENSIONS && 1492 extension.GetSyncType() == Extension::SYNC_TYPE_EXTENSION) { 1493 return true; 1494 } 1495 1496 if (type == syncer::APPS && 1497 extension.GetSyncType() == Extension::SYNC_TYPE_APP) { 1498 return true; 1499 } 1500 1501 return false; 1502} 1503 1504bool ExtensionService::ProcessExtensionSyncDataHelper( 1505 const extensions::ExtensionSyncData& extension_sync_data, 1506 syncer::ModelType type) { 1507 const std::string& id = extension_sync_data.id(); 1508 const Extension* extension = GetInstalledExtension(id); 1509 1510 // TODO(bolms): we should really handle this better. The particularly bad 1511 // case is where an app becomes an extension or vice versa, and we end up with 1512 // a zombie extension that won't go away. 1513 if (extension && !IsCorrectSyncType(*extension, type)) 1514 return true; 1515 1516 // Handle uninstalls first. 1517 if (extension_sync_data.uninstalled()) { 1518 std::string error; 1519 if (!UninstallExtensionHelper(this, id)) { 1520 LOG(WARNING) << "Could not uninstall extension " << id 1521 << " for sync"; 1522 } 1523 return true; 1524 } 1525 1526 // Extension from sync was uninstalled by the user as external extensions. 1527 // Honor user choice and skip installation/enabling. 1528 if (IsExternalExtensionUninstalled(id)) { 1529 LOG(WARNING) << "Extension with id " << id 1530 << " from sync was uninstalled as external extension"; 1531 return true; 1532 } 1533 1534 // Set user settings. 1535 if (extension_sync_data.enabled()) 1536 EnableExtension(id); 1537 else 1538 DisableExtension(id, Extension::DISABLE_USER_ACTION); 1539 1540 // We need to cache some version information here because setting the 1541 // incognito flag invalidates the |extension| pointer (it reloads the 1542 // extension). 1543 bool extension_installed = (extension != NULL); 1544 int result = extension ? 1545 extension->version()->CompareTo(extension_sync_data.version()) : 0; 1546 SetIsIncognitoEnabled(id, extension_sync_data.incognito_enabled()); 1547 extension = NULL; // No longer safe to use. 1548 1549 if (extension_installed) { 1550 // If the extension is already installed, check if it's outdated. 1551 if (result < 0) { 1552 // Extension is outdated. 1553 return false; 1554 } 1555 } else { 1556 // TODO(akalin): Replace silent update with a list of enabled 1557 // permissions. 1558 const bool kInstallSilently = true; 1559 1560 CHECK(type == syncer::EXTENSIONS || type == syncer::APPS); 1561 ExtensionFilter filter = 1562 (type == syncer::APPS) ? IsSyncableApp : IsSyncableExtension; 1563 1564 if (!pending_extension_manager()->AddFromSync( 1565 id, 1566 extension_sync_data.update_url(), 1567 filter, 1568 kInstallSilently)) { 1569 LOG(WARNING) << "Could not add pending extension for " << id; 1570 // This means that the extension is already pending installation, with a 1571 // non-INTERNAL location. Add to pending_sync_data, even though it will 1572 // never be removed (we'll never install a syncable version of the 1573 // extension), so that GetAllSyncData() continues to send it. 1574 } 1575 // Track pending extensions so that we can return them in GetAllSyncData(). 1576 return false; 1577 } 1578 1579 return true; 1580} 1581 1582bool ExtensionService::IsIncognitoEnabled( 1583 const std::string& extension_id) const { 1584 // If this is an existing component extension we always allow it to 1585 // work in incognito mode. 1586 const Extension* extension = GetInstalledExtension(extension_id); 1587 if (extension && extension->location() == Extension::COMPONENT) 1588 return true; 1589 1590 // Check the prefs. 1591 return extension_prefs_->IsIncognitoEnabled(extension_id); 1592} 1593 1594void ExtensionService::SetIsIncognitoEnabled( 1595 const std::string& extension_id, bool enabled) { 1596 const Extension* extension = GetInstalledExtension(extension_id); 1597 if (extension && extension->location() == Extension::COMPONENT) { 1598 // This shouldn't be called for component extensions unless they are 1599 // syncable. 1600 DCHECK(extension->IsSyncable()); 1601 1602 // If we are here, make sure the we aren't trying to change the value. 1603 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id)); 1604 1605 return; 1606 } 1607 1608 // Broadcast unloaded and loaded events to update browser state. Only bother 1609 // if the value changed and the extension is actually enabled, since there is 1610 // no UI otherwise. 1611 bool old_enabled = extension_prefs_->IsIncognitoEnabled(extension_id); 1612 if (enabled == old_enabled) 1613 return; 1614 1615 extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled); 1616 1617 bool extension_is_enabled = extensions_.Contains(extension_id); 1618 1619 // When we reload the extension the ID may be invalidated if we've passed it 1620 // by const ref everywhere. Make a copy to be safe. 1621 std::string id = extension_id; 1622 if (extension_is_enabled) 1623 ReloadExtension(id); 1624 1625 // Reloading the extension invalidates the |extension| pointer. 1626 extension = GetInstalledExtension(id); 1627 if (extension) 1628 SyncExtensionChangeIfNeeded(*extension); 1629} 1630 1631void ExtensionService::SetAppNotificationSetupDone( 1632 const std::string& extension_id, 1633 const std::string& oauth_client_id) { 1634 const Extension* extension = GetInstalledExtension(extension_id); 1635 // This method is called when the user sets up app notifications. 1636 // So it is not expected to be called until the extension is installed. 1637 if (!extension) { 1638 NOTREACHED(); 1639 return; 1640 } 1641 extension_prefs_->SetAppNotificationClientId(extension_id, oauth_client_id); 1642 SyncExtensionChangeIfNeeded(*extension); 1643} 1644 1645void ExtensionService::SetAppNotificationDisabled( 1646 const std::string& extension_id, 1647 bool value) { 1648 const Extension* extension = GetInstalledExtension(extension_id); 1649 // This method is called when the user enables/disables app notifications. 1650 // So it is not expected to be called until the extension is installed. 1651 if (!extension) { 1652 NOTREACHED(); 1653 return; 1654 } 1655 if (value) 1656 UMA_HISTOGRAM_COUNTS("Apps.SetAppNotificationsDisabled", 1); 1657 else 1658 UMA_HISTOGRAM_COUNTS("Apps.SetAppNotificationsEnabled", 1); 1659 extension_prefs_->SetAppNotificationDisabled(extension_id, value); 1660 SyncExtensionChangeIfNeeded(*extension); 1661} 1662 1663bool ExtensionService::CanCrossIncognito(const Extension* extension) const { 1664 // We allow the extension to see events and data from another profile iff it 1665 // uses "spanning" behavior and it has incognito access. "split" mode 1666 // extensions only see events for a matching profile. 1667 CHECK(extension); 1668 return IsIncognitoEnabled(extension->id()) && 1669 !extension->incognito_split_mode(); 1670} 1671 1672bool ExtensionService::CanLoadInIncognito(const Extension* extension) const { 1673 if (extension->is_hosted_app()) 1674 return true; 1675 // Packaged apps and regular extensions need to be enabled specifically for 1676 // incognito (and split mode should be set). 1677 return extension->incognito_split_mode() && 1678 IsIncognitoEnabled(extension->id()); 1679} 1680 1681void ExtensionService::OnExtensionMoved( 1682 const std::string& moved_extension_id, 1683 const std::string& predecessor_extension_id, 1684 const std::string& successor_extension_id) { 1685 extension_prefs_->extension_sorting()->OnExtensionMoved( 1686 moved_extension_id, 1687 predecessor_extension_id, 1688 successor_extension_id); 1689 1690 const Extension* extension = GetInstalledExtension(moved_extension_id); 1691 if (extension) 1692 SyncExtensionChangeIfNeeded(*extension); 1693} 1694 1695bool ExtensionService::AllowFileAccess(const Extension* extension) const { 1696 return (CommandLine::ForCurrentProcess()->HasSwitch( 1697 switches::kDisableExtensionsFileAccessCheck) || 1698 extension_prefs_->AllowFileAccess(extension->id())); 1699} 1700 1701void ExtensionService::SetAllowFileAccess(const Extension* extension, 1702 bool allow) { 1703 // Reload to update browser state. Only bother if the value changed and the 1704 // extension is actually enabled, since there is no UI otherwise. 1705 bool old_allow = AllowFileAccess(extension); 1706 if (allow == old_allow) 1707 return; 1708 1709 extension_prefs_->SetAllowFileAccess(extension->id(), allow); 1710 1711 bool extension_is_enabled = extensions_.Contains(extension->id()); 1712 if (extension_is_enabled) 1713 ReloadExtension(extension->id()); 1714} 1715 1716// Some extensions will autoupdate themselves externally from Chrome. These 1717// are typically part of some larger client application package. To support 1718// these, the extension will register its location in the the preferences file 1719// (and also, on Windows, in the registry) and this code will periodically 1720// check that location for a .crx file, which it will then install locally if 1721// a new version is available. 1722// Errors are reported through ExtensionErrorReporter. Succcess is not 1723// reported. 1724void ExtensionService::CheckForExternalUpdates() { 1725 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1726 1727 // Note that this installation is intentionally silent (since it didn't 1728 // go through the front-end). Extensions that are registered in this 1729 // way are effectively considered 'pre-bundled', and so implicitly 1730 // trusted. In general, if something has HKLM or filesystem access, 1731 // they could install an extension manually themselves anyway. 1732 1733 // Ask each external extension provider to give us a call back for each 1734 // extension they know about. See OnExternalExtension(File|UpdateUrl)Found. 1735 extensions::ProviderCollection::const_iterator i; 1736 for (i = external_extension_providers_.begin(); 1737 i != external_extension_providers_.end(); ++i) { 1738 extensions::ExternalProviderInterface* provider = i->get(); 1739 provider->VisitRegisteredExtension(); 1740 } 1741 1742 // Do any required work that we would have done after completion of all 1743 // providers. 1744 if (external_extension_providers_.empty()) { 1745 OnAllExternalProvidersReady(); 1746 } 1747} 1748 1749void ExtensionService::OnExternalProviderReady( 1750 const extensions::ExternalProviderInterface* provider) { 1751 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1752 CHECK(provider->IsReady()); 1753 1754 // An external provider has finished loading. We only take action 1755 // if all of them are finished. So we check them first. 1756 if (AreAllExternalProvidersReady()) 1757 OnAllExternalProvidersReady(); 1758} 1759 1760bool ExtensionService::AreAllExternalProvidersReady() const { 1761 extensions::ProviderCollection::const_iterator i; 1762 for (i = external_extension_providers_.begin(); 1763 i != external_extension_providers_.end(); ++i) { 1764 if (!i->get()->IsReady()) 1765 return false; 1766 } 1767 return true; 1768} 1769 1770void ExtensionService::OnAllExternalProvidersReady() { 1771 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1772 base::TimeDelta elapsed = base::Time::Now() - profile_->GetStartTime(); 1773 UMA_HISTOGRAM_TIMES("Extension.ExternalProvidersReadyAfter", elapsed); 1774 1775 // Install any pending extensions. 1776 if (update_once_all_providers_are_ready_ && updater()) { 1777 update_once_all_providers_are_ready_ = false; 1778 updater()->CheckNow(); 1779 } 1780 1781 // Uninstall all the unclaimed extensions. 1782 scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> extensions_info( 1783 extension_prefs_->GetInstalledExtensionsInfo()); 1784 for (size_t i = 0; i < extensions_info->size(); ++i) { 1785 ExtensionInfo* info = extensions_info->at(i).get(); 1786 if (Extension::IsExternalLocation(info->extension_location)) 1787 CheckExternalUninstall(info->extension_id); 1788 } 1789 IdentifyAlertableExtensions(); 1790} 1791 1792void ExtensionService::IdentifyAlertableExtensions() { 1793 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1794 1795 // Build up the lists of extensions that require acknowledgment. If this is 1796 // the first time, grandfather extensions that would have caused 1797 // notification. 1798 extension_error_ui_.reset(ExtensionErrorUI::Create(this)); 1799 1800 bool did_show_alert = false; 1801 if (PopulateExtensionErrorUI(extension_error_ui_.get())) { 1802 if (extension_prefs_->SetAlertSystemFirstRun()) { 1803 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1804 did_show_alert = extension_error_ui_->ShowErrorInBubbleView(); 1805 } else { 1806 // First run. Just acknowledge all the extensions, silently, by 1807 // shortcutting the display of the UI and going straight to the 1808 // callback for pressing the Accept button. 1809 HandleExtensionAlertAccept(); 1810 } 1811 } 1812 1813 UpdateExternalExtensionAlert(); 1814 1815 if (!did_show_alert) 1816 extension_error_ui_.reset(); 1817} 1818 1819bool ExtensionService::PopulateExtensionErrorUI( 1820 ExtensionErrorUI* extension_error_ui) { 1821 bool needs_alert = false; 1822 for (ExtensionSet::const_iterator iter = extensions_.begin(); 1823 iter != extensions_.end(); ++iter) { 1824 const Extension* e = *iter; 1825 if (!extension_prefs_->UserMayLoad(e, NULL)) { 1826 if (!extension_prefs_->IsBlacklistedExtensionAcknowledged(e->id())) { 1827 extension_error_ui->AddBlacklistedExtension(e->id()); 1828 needs_alert = true; 1829 } 1830 } 1831 if (extension_prefs_->IsExtensionOrphaned(e->id())) { 1832 if (!extension_prefs_->IsOrphanedExtensionAcknowledged(e->id())) { 1833 extension_error_ui->AddOrphanedExtension(e->id()); 1834 needs_alert = true; 1835 } 1836 } 1837 } 1838 return needs_alert; 1839} 1840 1841void ExtensionService::HandleExtensionAlertClosed() { 1842 extension_error_ui_.reset(); 1843} 1844 1845void ExtensionService::HandleExtensionAlertAccept() { 1846 const ExtensionIdSet* extension_ids = 1847 extension_error_ui_->get_blacklisted_extension_ids(); 1848 for (ExtensionIdSet::const_iterator iter = extension_ids->begin(); 1849 iter != extension_ids->end(); ++iter) { 1850 extension_prefs_->AcknowledgeBlacklistedExtension(*iter); 1851 } 1852 extension_ids = extension_error_ui_->get_orphaned_extension_ids(); 1853 for (ExtensionIdSet::const_iterator iter = extension_ids->begin(); 1854 iter != extension_ids->end(); ++iter) { 1855 extension_prefs_->AcknowledgeOrphanedExtension(*iter); 1856 } 1857} 1858 1859void ExtensionService::AcknowledgeExternalExtension(const std::string& id) { 1860 extension_prefs_->AcknowledgeExternalExtension(id); 1861 UpdateExternalExtensionAlert(); 1862} 1863 1864bool ExtensionService::IsUnacknowledgedExternalExtension( 1865 const Extension* extension) { 1866 if (!FeatureSwitch::prompt_for_external_extensions()->IsEnabled()) 1867 return false; 1868 1869 return (Extension::IsExternalLocation(extension->location()) && 1870 !extension_prefs_->IsExternalExtensionAcknowledged(extension->id()) && 1871 !(extension_prefs_->GetDisableReasons(extension->id()) & 1872 Extension::DISABLE_SIDELOAD_WIPEOUT)); 1873} 1874 1875void ExtensionService::HandleExtensionAlertDetails() { 1876 extension_error_ui_->ShowExtensions(); 1877} 1878 1879void ExtensionService::UpdateExternalExtensionAlert() { 1880 if (!FeatureSwitch::prompt_for_external_extensions()->IsEnabled()) 1881 return; 1882 1883 const Extension* extension = NULL; 1884 for (ExtensionSet::const_iterator iter = disabled_extensions_.begin(); 1885 iter != disabled_extensions_.end(); ++iter) { 1886 const Extension* e = *iter; 1887 if (IsUnacknowledgedExternalExtension(e)) { 1888 extension = e; 1889 break; 1890 } 1891 } 1892 1893 if (extension) { 1894 if (!extensions::HasExternalInstallError(this)) { 1895 if (extension_prefs_->IncrementAcknowledgePromptCount(extension->id()) > 1896 kMaxExtensionAcknowledgePromptCount) { 1897 // Stop prompting for this extension, and check if there's another 1898 // one that needs prompting. 1899 extension_prefs_->AcknowledgeExternalExtension(extension->id()); 1900 UpdateExternalExtensionAlert(); 1901 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent", 1902 EXTERNAL_EXTENSION_IGNORED, 1903 EXTERNAL_EXTENSION_BUCKET_BOUNDARY); 1904 return; 1905 } 1906 extensions::AddExternalInstallError(this, extension); 1907 } 1908 } else { 1909 extensions::RemoveExternalInstallError(this); 1910 } 1911} 1912 1913void ExtensionService::UnloadExtension( 1914 const std::string& extension_id, 1915 extension_misc::UnloadedExtensionReason reason) { 1916 // Make sure the extension gets deleted after we return from this function. 1917 int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED; 1918 scoped_refptr<const Extension> extension( 1919 GetExtensionByIdInternal(extension_id, include_mask)); 1920 1921 // This method can be called via PostTask, so the extension may have been 1922 // unloaded by the time this runs. 1923 if (!extension) { 1924 // In case the extension may have crashed/uninstalled. Allow the profile to 1925 // clean up its RequestContexts. 1926 system_->UnregisterExtensionWithRequestContexts(extension_id, reason); 1927 return; 1928 } 1929 1930 // Keep information about the extension so that we can reload it later 1931 // even if it's not permanently installed. 1932 unloaded_extension_paths_[extension->id()] = extension->path(); 1933 1934 // Clean up if the extension is meant to be enabled after a reload. 1935 disabled_extension_paths_.erase(extension->id()); 1936 1937 // Clean up runtime data. 1938 extension_runtime_data_.erase(extension_id); 1939 1940 if (disabled_extensions_.Contains(extension->id())) { 1941 UnloadedExtensionInfo details(extension, reason); 1942 details.already_disabled = true; 1943 disabled_extensions_.Remove(extension->id()); 1944 content::NotificationService::current()->Notify( 1945 chrome::NOTIFICATION_EXTENSION_UNLOADED, 1946 content::Source<Profile>(profile_), 1947 content::Details<UnloadedExtensionInfo>(&details)); 1948 // Make sure the profile cleans up its RequestContexts when an already 1949 // disabled extension is unloaded (since they are also tracking the disabled 1950 // extensions). 1951 system_->UnregisterExtensionWithRequestContexts(extension_id, reason); 1952 return; 1953 } 1954 1955 // Remove the extension from our list. 1956 extensions_.Remove(extension->id()); 1957 1958 NotifyExtensionUnloaded(extension.get(), reason); 1959} 1960 1961void ExtensionService::UnloadAllExtensions() { 1962 profile_->GetExtensionSpecialStoragePolicy()->RevokeRightsForAllExtensions(); 1963 1964 extensions_.Clear(); 1965 disabled_extensions_.Clear(); 1966 terminated_extensions_.Clear(); 1967 extension_runtime_data_.clear(); 1968 1969 // TODO(erikkay) should there be a notification for this? We can't use 1970 // EXTENSION_UNLOADED since that implies that the extension has been disabled 1971 // or uninstalled, and UnloadAll is just part of shutdown. 1972} 1973 1974void ExtensionService::ReloadExtensions() { 1975 UnloadAllExtensions(); 1976 component_loader_->LoadAll(); 1977 extensions::InstalledLoader(this).LoadAllExtensions(); 1978} 1979 1980void ExtensionService::GarbageCollectExtensions() { 1981 if (extension_prefs_->pref_service()->ReadOnly()) 1982 return; 1983 1984 scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> info( 1985 extension_prefs_->GetInstalledExtensionsInfo()); 1986 1987 std::multimap<std::string, FilePath> extension_paths; 1988 for (size_t i = 0; i < info->size(); ++i) 1989 extension_paths.insert(std::make_pair(info->at(i)->extension_id, 1990 info->at(i)->extension_path)); 1991 1992 info = extension_prefs_->GetAllIdleInstallInfo(); 1993 for (size_t i = 0; i < info->size(); ++i) 1994 extension_paths.insert(std::make_pair(info->at(i)->extension_id, 1995 info->at(i)->extension_path)); 1996 1997 if (!BrowserThread::PostTask( 1998 BrowserThread::FILE, FROM_HERE, 1999 base::Bind( 2000 &extension_file_util::GarbageCollectExtensions, 2001 install_directory_, 2002 extension_paths))) { 2003 NOTREACHED(); 2004 } 2005 2006#if defined(ENABLE_THEMES) 2007 // Also garbage-collect themes. We check |profile_| to be 2008 // defensive; in the future, we may call GarbageCollectExtensions() 2009 // from somewhere other than Init() (e.g., in a timer). 2010 if (profile_) { 2011 ThemeServiceFactory::GetForProfile(profile_)->RemoveUnusedThemes(); 2012 } 2013#endif 2014} 2015 2016void ExtensionService::SyncExtensionChangeIfNeeded(const Extension& extension) { 2017 if (app_sync_bundle_.HandlesApp(extension)) { 2018 app_sync_bundle_.SyncChangeIfNeeded(extension); 2019 } else if (extension_sync_bundle_.HandlesExtension(extension)) { 2020 extension_sync_bundle_.SyncChangeIfNeeded(extension); 2021 } 2022} 2023 2024void ExtensionService::OnLoadedInstalledExtensions() { 2025 if (updater_.get()) 2026 updater_->Start(); 2027 2028 ready_ = true; 2029 content::NotificationService::current()->Notify( 2030 chrome::NOTIFICATION_EXTENSIONS_READY, 2031 content::Source<Profile>(profile_), 2032 content::NotificationService::NoDetails()); 2033} 2034 2035void ExtensionService::AddExtension(const Extension* extension) { 2036 // Ensure extension is deleted unless we transfer ownership. 2037 scoped_refptr<const Extension> scoped_extension(extension); 2038 2039 // TODO(jstritar): We may be able to get rid of this branch by overriding the 2040 // default extension state to DISABLED when the --disable-extensions flag 2041 // is set (http://crbug.com/29067). 2042 if (!extensions_enabled() && 2043 !extension->is_theme() && 2044 extension->location() != Extension::COMPONENT && 2045 !Extension::IsExternalLocation(extension->location())) { 2046 return; 2047 } 2048 2049 SetBeingUpgraded(extension, false); 2050 2051 // The extension is now loaded, remove its data from unloaded extension map. 2052 unloaded_extension_paths_.erase(extension->id()); 2053 2054 // If a terminated extension is loaded, remove it from the terminated list. 2055 UntrackTerminatedExtension(extension->id()); 2056 2057 // If the extension was disabled for a reload, then enable it. 2058 if (disabled_extension_paths_.erase(extension->id()) > 0) 2059 EnableExtension(extension->id()); 2060 2061 // Check if the extension's privileges have changed and disable the 2062 // extension if necessary. 2063 InitializePermissions(extension); 2064 2065 // If this extension is a sideloaded extension and we've not performed a 2066 // wipeout before, we might disable this extension here. 2067 MaybeWipeout(extension); 2068 2069 if (extension_prefs_->IsExtensionDisabled(extension->id())) { 2070 disabled_extensions_.Insert(scoped_extension); 2071 SyncExtensionChangeIfNeeded(*extension); 2072 content::NotificationService::current()->Notify( 2073 chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, 2074 content::Source<Profile>(profile_), 2075 content::Details<const Extension>(extension)); 2076 2077 if (extension_prefs_->GetDisableReasons(extension->id()) & 2078 Extension::DISABLE_PERMISSIONS_INCREASE) { 2079 extensions::AddExtensionDisabledError(this, extension); 2080 } 2081 return; 2082 } 2083 2084 // All apps that are displayed in the launcher are ordered by their ordinals 2085 // so we must ensure they have valid ordinals. 2086 if (extension->RequiresSortOrdinal()) { 2087 extension_prefs_->extension_sorting()->EnsureValidOrdinals( 2088 extension->id(), syncer::StringOrdinal()); 2089 } 2090 2091 extensions_.Insert(scoped_extension); 2092 SyncExtensionChangeIfNeeded(*extension); 2093 NotifyExtensionLoaded(extension); 2094 DoPostLoadTasks(extension); 2095} 2096 2097void ExtensionService::InitializePermissions(const Extension* extension) { 2098 // If the extension has used the optional permissions API, it will have a 2099 // custom set of active permissions defined in the extension prefs. Here, 2100 // we update the extension's active permissions based on the prefs. 2101 scoped_refptr<PermissionSet> active_permissions = 2102 extension_prefs()->GetActivePermissions(extension->id()); 2103 2104 if (active_permissions.get()) { 2105 // We restrict the active permissions to be within the bounds defined in the 2106 // extension's manifest. 2107 // a) active permissions must be a subset of optional + default permissions 2108 // b) active permissions must contains all default permissions 2109 scoped_refptr<PermissionSet> total_permissions = 2110 PermissionSet::CreateUnion( 2111 extension->required_permission_set(), 2112 extension->optional_permission_set()); 2113 2114 // Make sure the active permissions contain no more than optional + default. 2115 scoped_refptr<PermissionSet> adjusted_active = 2116 PermissionSet::CreateIntersection( 2117 total_permissions.get(), active_permissions.get()); 2118 2119 // Make sure the active permissions contain the default permissions. 2120 adjusted_active = PermissionSet::CreateUnion( 2121 extension->required_permission_set(), adjusted_active.get()); 2122 2123 extensions::PermissionsUpdater perms_updater(profile()); 2124 perms_updater.UpdateActivePermissions(extension, adjusted_active); 2125 } 2126 2127 // We keep track of all permissions the user has granted each extension. 2128 // This allows extensions to gracefully support backwards compatibility 2129 // by including unknown permissions in their manifests. When the user 2130 // installs the extension, only the recognized permissions are recorded. 2131 // When the unknown permissions become recognized (e.g., through browser 2132 // upgrade), we can prompt the user to accept these new permissions. 2133 // Extensions can also silently upgrade to less permissions, and then 2134 // silently upgrade to a version that adds these permissions back. 2135 // 2136 // For example, pretend that Chrome 10 includes a permission "omnibox" 2137 // for an API that adds suggestions to the omnibox. An extension can 2138 // maintain backwards compatibility while still having "omnibox" in the 2139 // manifest. If a user installs the extension on Chrome 9, the browser 2140 // will record the permissions it recognized, not including "omnibox." 2141 // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome 2142 // will disable the extension and prompt the user to approve the increase 2143 // in privileges. The extension could then release a new version that 2144 // removes the "omnibox" permission. When the user upgrades, Chrome will 2145 // still remember that "omnibox" had been granted, so that if the 2146 // extension once again includes "omnibox" in an upgrade, the extension 2147 // can upgrade without requiring this user's approval. 2148 int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED; 2149 const Extension* old = 2150 GetExtensionByIdInternal(extension->id(), include_mask); 2151 bool is_extension_upgrade = old != NULL; 2152 bool is_privilege_increase = false; 2153 bool previously_disabled = false; 2154 int disable_reasons = extension_prefs_->GetDisableReasons(extension->id()); 2155 2156 // We only need to compare the granted permissions to the current permissions 2157 // if the extension is not allowed to silently increase its permissions. 2158 bool is_default_app_install = 2159 (!is_extension_upgrade && extension->was_installed_by_default()); 2160 if (!(extension->CanSilentlyIncreasePermissions() 2161 || is_default_app_install)) { 2162 // Add all the recognized permissions if the granted permissions list 2163 // hasn't been initialized yet. 2164 scoped_refptr<PermissionSet> granted_permissions = 2165 extension_prefs_->GetGrantedPermissions(extension->id()); 2166 CHECK(granted_permissions.get()); 2167 2168 // Here, we check if an extension's privileges have increased in a manner 2169 // that requires the user's approval. This could occur because the browser 2170 // upgraded and recognized additional privileges, or an extension upgrades 2171 // to a version that requires additional privileges. 2172 is_privilege_increase = 2173 granted_permissions->HasLessPrivilegesThan( 2174 extension->GetActivePermissions()); 2175 } 2176 2177 // Silently grant all active permissions to default apps only on install. 2178 // After install they should behave like other apps. 2179 if (is_default_app_install) 2180 GrantPermissions(extension, true); 2181 2182 if (is_extension_upgrade) { 2183 // Other than for unpacked extensions, CrxInstaller should have guaranteed 2184 // that we aren't downgrading. 2185 if (extension->location() != Extension::LOAD) 2186 CHECK_GE(extension->version()->CompareTo(*(old->version())), 0); 2187 2188 // Extensions get upgraded if the privileges are allowed to increase or 2189 // the privileges haven't increased. 2190 if (!is_privilege_increase) { 2191 SetBeingUpgraded(old, true); 2192 SetBeingUpgraded(extension, true); 2193 } 2194 2195 // If the extension was already disabled, suppress any alerts for becoming 2196 // disabled on permissions increase. 2197 previously_disabled = extension_prefs_->IsExtensionDisabled(old->id()); 2198 if (previously_disabled) { 2199 int reasons = extension_prefs_->GetDisableReasons(old->id()); 2200 if (reasons == Extension::DISABLE_NONE) { 2201 // Initialize the reason for legacy disabled extensions from whether the 2202 // extension already exceeded granted permissions. 2203 if (extension_prefs_->DidExtensionEscalatePermissions(old->id())) 2204 disable_reasons = Extension::DISABLE_PERMISSIONS_INCREASE; 2205 else 2206 disable_reasons = Extension::DISABLE_USER_ACTION; 2207 } 2208 } else { 2209 disable_reasons = Extension::DISABLE_PERMISSIONS_INCREASE; 2210 } 2211 2212 // To upgrade an extension in place, unload the old one and 2213 // then load the new one. 2214 UnloadExtension(old->id(), extension_misc::UNLOAD_REASON_UPDATE); 2215 old = NULL; 2216 } 2217 2218 // Extension has changed permissions significantly. Disable it. A 2219 // notification should be sent by the caller. 2220 if (is_privilege_increase) { 2221 if (!extension_prefs_->DidExtensionEscalatePermissions(extension->id())) { 2222 RecordPermissionMessagesHistogram( 2223 extension, "Extensions.Permissions_AutoDisable"); 2224 } 2225 extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED); 2226 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true); 2227 extension_prefs_->AddDisableReason( 2228 extension->id(), 2229 static_cast<Extension::DisableReason>(disable_reasons)); 2230 } 2231} 2232 2233void ExtensionService::MaybeWipeout( 2234 const extensions::Extension* extension) { 2235 if (!FeatureSwitch::sideload_wipeout()->IsEnabled()) 2236 return; 2237 2238 bool done = extension_prefs_->GetSideloadWipeoutDone() || 2239 extension_prefs_->IsExternalExtensionExcludedFromWipeout(extension->id()); 2240 if (done) 2241 return; 2242 2243 Extension::Type type = extension->GetType(); 2244 int disable_reasons = extension_prefs_->GetDisableReasons(extension->id()); 2245 if (disable_reasons == Extension::DISABLE_NONE && 2246 type == Extension::TYPE_EXTENSION) { 2247 Extension::Location location = extension->location(); 2248 if (location == Extension::EXTERNAL_REGISTRY || 2249 (location == Extension::INTERNAL && !extension->UpdatesFromGallery())) { 2250 extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED); 2251 extension_prefs_->AddDisableReason( 2252 extension->id(), 2253 static_cast<Extension::DisableReason>( 2254 Extension::DISABLE_SIDELOAD_WIPEOUT)); 2255 } 2256 } 2257} 2258 2259void ExtensionService::UpdateActiveExtensionsInCrashReporter() { 2260 std::set<std::string> extension_ids; 2261 for (ExtensionSet::const_iterator iter = extensions_.begin(); 2262 iter != extensions_.end(); ++iter) { 2263 const Extension* extension = *iter; 2264 if (!extension->is_theme() && extension->location() != Extension::COMPONENT) 2265 extension_ids.insert(extension->id()); 2266 } 2267 2268 child_process_logging::SetActiveExtensions(extension_ids); 2269} 2270 2271void ExtensionService::OnExtensionInstalled( 2272 const Extension* extension, 2273 const syncer::StringOrdinal& page_ordinal, 2274 bool has_requirement_errors, 2275 bool wait_for_idle) { 2276 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2277 2278 // Ensure extension is deleted unless we transfer ownership. 2279 scoped_refptr<const Extension> scoped_extension(extension); 2280 const std::string& id = extension->id(); 2281 bool initial_enable = ShouldEnableOnInstall(extension); 2282 const extensions::PendingExtensionInfo* pending_extension_info = NULL; 2283 if ((pending_extension_info = pending_extension_manager()->GetById(id))) { 2284 if (!pending_extension_info->ShouldAllowInstall(*extension)) { 2285 pending_extension_manager()->Remove(id); 2286 2287 LOG(WARNING) << "ShouldAllowInstall() returned false for " 2288 << id << " of type " << extension->GetType() 2289 << " and update URL " << extension->update_url().spec() 2290 << "; not installing"; 2291 2292 content::NotificationService::current()->Notify( 2293 chrome::NOTIFICATION_EXTENSION_INSTALL_NOT_ALLOWED, 2294 content::Source<Profile>(profile_), 2295 content::Details<const Extension>(extension)); 2296 2297 // Delete the extension directory since we're not going to 2298 // load it. 2299 if (!BrowserThread::PostTask( 2300 BrowserThread::FILE, FROM_HERE, 2301 base::Bind(&extension_file_util::DeleteFile, 2302 extension->path(), true))) { 2303 NOTREACHED(); 2304 } 2305 return; 2306 } 2307 2308 pending_extension_manager()->Remove(id); 2309 } else { 2310 // We explicitly want to re-enable an uninstalled external 2311 // extension; if we're here, that means the user is manually 2312 // installing the extension. 2313 if (IsExternalExtensionUninstalled(id)) { 2314 initial_enable = true; 2315 } 2316 } 2317 2318 // Unsupported requirements overrides the management policy. 2319 if (has_requirement_errors) { 2320 initial_enable = false; 2321 extension_prefs_->AddDisableReason( 2322 id, Extension::DISABLE_UNSUPPORTED_REQUIREMENT); 2323 // If the extension was disabled because of unsupported requirements but 2324 // now supports all requirements after an update and there are not other 2325 // disable reasons, enable it. 2326 } else if (extension_prefs_->GetDisableReasons(id) == 2327 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) { 2328 initial_enable = true; 2329 extension_prefs_->ClearDisableReasons(id); 2330 } 2331 2332 int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED; 2333 // Do not record the install histograms for upgrades. 2334 if (!GetExtensionByIdInternal(extension->id(), include_mask)) { 2335 UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType", 2336 extension->GetType(), 100); 2337 RecordPermissionMessagesHistogram( 2338 extension, "Extensions.Permissions_Install"); 2339 } 2340 2341 // Certain extension locations are specific enough that we can 2342 // auto-acknowledge any extension that came from one of them. 2343 if (extension->location() == Extension::EXTERNAL_POLICY_DOWNLOAD) 2344 AcknowledgeExternalExtension(extension->id()); 2345 2346 const Extension* old = 2347 GetExtensionByIdInternal(id, include_mask); 2348 // If this is an upgrade and the extension/app has a background page that can 2349 // be idle but isn't, we delay the upgrade until the background page is idle. 2350 if (wait_for_idle && old && !IsExtensionIdle(id) && 2351 !old->has_persistent_background_page()) { 2352 extension_prefs_->SetIdleInstallInfo( 2353 extension, 2354 initial_enable ? Extension::ENABLED : Extension::DISABLED); 2355 2356 // Transfer ownership of |extension|. 2357 pending_extension_updates_.Insert(scoped_extension); 2358 2359 // Notify extension of available update. 2360 extensions::RuntimeEventRouter::DispatchOnUpdateAvailableEvent( 2361 profile_, id, extension->manifest()->value()); 2362 return; 2363 } 2364 2365 extension_prefs_->OnExtensionInstalled( 2366 extension, 2367 initial_enable ? Extension::ENABLED : Extension::DISABLED, 2368 page_ordinal); 2369 2370 // Unpacked extensions default to allowing file access, but if that has been 2371 // overridden, don't reset the value. 2372 if (Extension::ShouldAlwaysAllowFileAccess(extension->location()) && 2373 !extension_prefs_->HasAllowFileAccessSetting(id)) { 2374 extension_prefs_->SetAllowFileAccess(id, true); 2375 } 2376 2377 content::NotificationService::current()->Notify( 2378 chrome::NOTIFICATION_EXTENSION_INSTALLED, 2379 content::Source<Profile>(profile_), 2380 content::Details<const Extension>(extension)); 2381 2382 bool unacknowledged_external = IsUnacknowledgedExternalExtension(extension); 2383 2384 // Transfer ownership of |extension| to AddExtension. 2385 AddExtension(scoped_extension); 2386 2387 // If this is a new external extension that was disabled, alert the user 2388 // so he can reenable it. We do this last so that it has already been 2389 // added to our list of extensions. 2390 if (unacknowledged_external) { 2391 UpdateExternalExtensionAlert(); 2392 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent", 2393 EXTERNAL_EXTENSION_INSTALLED, 2394 EXTERNAL_EXTENSION_BUCKET_BOUNDARY); 2395 } 2396} 2397 2398void ExtensionService::MaybeFinishInstallation( 2399 const std::string& extension_id) { 2400 // Check if the extension already got updated. 2401 if (!pending_extension_updates_.Contains(extension_id)) 2402 return; 2403 // Check if the extension is still idle. 2404 if (!IsExtensionIdle(extension_id)) 2405 return; 2406 2407 FinishInstallation(extension_id); 2408} 2409 2410void ExtensionService::FinishInstallation(const std::string& extension_id) { 2411 const Extension* extension = pending_extension_updates_.GetByID(extension_id); 2412 CHECK(extension); 2413 // Ensure extension is deleted unless we transfer ownership. 2414 scoped_refptr<const Extension> scoped_extension(extension); 2415 pending_extension_updates_.Remove(extension_id); 2416 2417 if (!extension_prefs_->FinishIdleInstallInfo(extension_id)) 2418 NOTREACHED(); 2419 2420 content::NotificationService::current()->Notify( 2421 chrome::NOTIFICATION_EXTENSION_INSTALLED, 2422 content::Source<Profile>(profile_), 2423 content::Details<const Extension>(extension)); 2424 2425 // Transfer ownership of |extension| to AddExtension. 2426 AddExtension(scoped_extension); 2427 2428 // If this is a new external extension that was disabled, alert the user 2429 // so he can reenable it. 2430 if (Extension::IsExternalLocation(extension->location()) && 2431 extension_prefs_->IsExtensionDisabled(extension_id)) 2432 UpdateExternalExtensionAlert(); 2433} 2434 2435const Extension* ExtensionService::GetExtensionByIdInternal( 2436 const std::string& id, int include_mask) const { 2437 std::string lowercase_id = StringToLowerASCII(id); 2438 if (include_mask & INCLUDE_ENABLED) { 2439 const Extension* extension = extensions_.GetByID(lowercase_id); 2440 if (extension) 2441 return extension; 2442 } 2443 if (include_mask & INCLUDE_DISABLED) { 2444 const Extension* extension = disabled_extensions_.GetByID(lowercase_id); 2445 if (extension) 2446 return extension; 2447 } 2448 if (include_mask & INCLUDE_TERMINATED) { 2449 const Extension* extension = terminated_extensions_.GetByID(lowercase_id); 2450 if (extension) 2451 return extension; 2452 } 2453 return NULL; 2454} 2455 2456void ExtensionService::TrackTerminatedExtension(const Extension* extension) { 2457 if (!terminated_extensions_.Contains(extension->id())) 2458 terminated_extensions_.Insert(make_scoped_refptr(extension)); 2459 2460 UnloadExtension(extension->id(), extension_misc::UNLOAD_REASON_TERMINATE); 2461} 2462 2463void ExtensionService::UntrackTerminatedExtension(const std::string& id) { 2464 std::string lowercase_id = StringToLowerASCII(id); 2465 terminated_extensions_.Remove(lowercase_id); 2466} 2467 2468const Extension* ExtensionService::GetTerminatedExtension( 2469 const std::string& id) const { 2470 return GetExtensionByIdInternal(id, INCLUDE_TERMINATED); 2471} 2472 2473const Extension* ExtensionService::GetInstalledExtension( 2474 const std::string& id) const { 2475 int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED | INCLUDE_TERMINATED; 2476 return GetExtensionByIdInternal(id, include_mask); 2477} 2478 2479bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) { 2480 // Allow bindings for all packaged extensions and component hosted apps. 2481 const Extension* extension = extensions_.GetExtensionOrAppByURL( 2482 ExtensionURLInfo(url)); 2483 return extension && (!extension->is_hosted_app() || 2484 extension->location() == Extension::COMPONENT); 2485} 2486 2487bool ExtensionService::ShouldBlockUrlInBrowserTab(GURL* url) { 2488 const Extension* extension = extensions_.GetExtensionOrAppByURL( 2489 ExtensionURLInfo(*url)); 2490 if (extension && extension->is_platform_app()) { 2491 *url = GURL(chrome::kExtensionInvalidRequestURL); 2492 return true; 2493 } 2494 2495 return false; 2496} 2497 2498gfx::Image ExtensionService::GetOmniboxIcon( 2499 const std::string& extension_id) { 2500 return gfx::Image(omnibox_icon_manager_.GetIcon(extension_id)); 2501} 2502 2503gfx::Image ExtensionService::GetOmniboxPopupIcon( 2504 const std::string& extension_id) { 2505 return gfx::Image(omnibox_popup_icon_manager_.GetIcon(extension_id)); 2506} 2507 2508bool ExtensionService::OnExternalExtensionFileFound( 2509 const std::string& id, 2510 const Version* version, 2511 const FilePath& path, 2512 Extension::Location location, 2513 int creation_flags, 2514 bool mark_acknowledged) { 2515 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2516 CHECK(Extension::IdIsValid(id)); 2517 if (extension_prefs_->IsExternalExtensionUninstalled(id)) 2518 return false; 2519 2520 // Before even bothering to unpack, check and see if we already have this 2521 // version. This is important because these extensions are going to get 2522 // installed on every startup. 2523 const Extension* existing = GetExtensionById(id, true); 2524 2525 if (existing) { 2526 // The default apps will have the location set as INTERNAL. Since older 2527 // default apps are installed as EXTERNAL, we override them. However, if the 2528 // app is already installed as internal, then do the version check. 2529 // TODO(grv) : Remove after Q1-2013. 2530 bool is_default_apps_migration = 2531 (location == Extension::INTERNAL && 2532 Extension::IsExternalLocation(existing->location())); 2533 2534 if (!is_default_apps_migration) { 2535 DCHECK(version); 2536 2537 switch (existing->version()->CompareTo(*version)) { 2538 case -1: // existing version is older, we should upgrade 2539 break; 2540 case 0: // existing version is same, do nothing 2541 return false; 2542 case 1: // existing version is newer, uh-oh 2543 LOG(WARNING) << "Found external version of extension " << id 2544 << "that is older than current version. Current version " 2545 << "is: " << existing->VersionString() << ". New " 2546 << "version is: " << version->GetString() 2547 << ". Keeping current version."; 2548 return false; 2549 } 2550 } 2551 } 2552 2553 // If the extension is already pending, don't start an install. 2554 if (!pending_extension_manager()->AddFromExternalFile( 2555 id, location, *version)) { 2556 return false; 2557 } 2558 2559 // no client (silent install) 2560 scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(this, NULL)); 2561 installer->set_install_source(location); 2562 installer->set_expected_id(id); 2563 installer->set_expected_version(*version); 2564 installer->set_install_cause(extension_misc::INSTALL_CAUSE_EXTERNAL_FILE); 2565 installer->set_creation_flags(creation_flags); 2566 installer->InstallCrx(path); 2567 2568 // Depending on the source, a new external extension might not need a user 2569 // notification on installation. For such extensions, mark them acknowledged 2570 // now to suppress the notification. 2571 if (mark_acknowledged) 2572 AcknowledgeExternalExtension(id); 2573 2574 return true; 2575} 2576 2577void ExtensionService::ReportExtensionLoadError( 2578 const FilePath& extension_path, 2579 const std::string &error, 2580 bool be_noisy) { 2581 content::NotificationService::current()->Notify( 2582 chrome::NOTIFICATION_EXTENSION_LOAD_ERROR, 2583 content::Source<Profile>(profile_), 2584 content::Details<const std::string>(&error)); 2585 2586 std::string path_str = UTF16ToUTF8(extension_path.LossyDisplayName()); 2587 string16 message = UTF8ToUTF16(base::StringPrintf( 2588 "Could not load extension from '%s'. %s", 2589 path_str.c_str(), error.c_str())); 2590 ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy); 2591} 2592 2593void ExtensionService::DidCreateRenderViewForBackgroundPage( 2594 extensions::ExtensionHost* host) { 2595 OrphanedDevTools::iterator iter = 2596 orphaned_dev_tools_.find(host->extension_id()); 2597 if (iter == orphaned_dev_tools_.end()) 2598 return; 2599 2600 DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost( 2601 host->render_view_host()); 2602 content::DevToolsManager::GetInstance()->AttachClientHost(iter->second, 2603 agent); 2604 orphaned_dev_tools_.erase(iter); 2605} 2606 2607void ExtensionService::Observe(int type, 2608 const content::NotificationSource& source, 2609 const content::NotificationDetails& details) { 2610 switch (type) { 2611 case chrome::NOTIFICATION_APP_TERMINATING: 2612 // Shutdown has started. Don't start any more extension installs. 2613 // (We cannot use ExtensionService::Shutdown() for this because it 2614 // happens too late in browser teardown.) 2615 browser_terminating_ = true; 2616 break; 2617 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: { 2618 if (profile_ != 2619 content::Source<Profile>(source).ptr()->GetOriginalProfile()) { 2620 break; 2621 } 2622 2623 extensions::ExtensionHost* host = 2624 content::Details<extensions::ExtensionHost>(details).ptr(); 2625 2626 // Mark the extension as terminated and Unload it. We want it to 2627 // be in a consistent state: either fully working or not loaded 2628 // at all, but never half-crashed. We do it in a PostTask so 2629 // that other handlers of this notification will still have 2630 // access to the Extension and ExtensionHost. 2631 MessageLoop::current()->PostTask( 2632 FROM_HERE, 2633 base::Bind( 2634 &ExtensionService::TrackTerminatedExtension, 2635 AsWeakPtr(), 2636 host->extension())); 2637 break; 2638 } 2639 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: { 2640 content::RenderProcessHost* process = 2641 content::Source<content::RenderProcessHost>(source).ptr(); 2642 Profile* host_profile = 2643 Profile::FromBrowserContext(process->GetBrowserContext()); 2644 if (!profile_->IsSameProfile(host_profile->GetOriginalProfile())) 2645 break; 2646 2647 // Extensions need to know the channel for API restrictions. 2648 process->Send(new ExtensionMsg_SetChannel( 2649 extensions::Feature::GetCurrentChannel())); 2650 2651 // Valid extension function names, used to setup bindings in renderer. 2652 std::vector<std::string> function_names; 2653 ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names); 2654 process->Send(new ExtensionMsg_SetFunctionNames(function_names)); 2655 2656 // Scripting whitelist. This is modified by tests and must be communicated 2657 // to renderers. 2658 process->Send(new ExtensionMsg_SetScriptingWhitelist( 2659 *Extension::GetScriptingWhitelist())); 2660 2661 // Loaded extensions. 2662 std::vector<ExtensionMsg_Loaded_Params> loaded_extensions; 2663 for (ExtensionSet::const_iterator iter = extensions_.begin(); 2664 iter != extensions_.end(); ++iter) { 2665 // Renderers don't need to know about themes. 2666 if (!(*iter)->is_theme()) 2667 loaded_extensions.push_back(ExtensionMsg_Loaded_Params(*iter)); 2668 } 2669 process->Send(new ExtensionMsg_Loaded(loaded_extensions)); 2670 break; 2671 } 2672 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { 2673 content::RenderProcessHost* process = 2674 content::Source<content::RenderProcessHost>(source).ptr(); 2675 Profile* host_profile = 2676 Profile::FromBrowserContext(process->GetBrowserContext()); 2677 if (!profile_->IsSameProfile(host_profile->GetOriginalProfile())) 2678 break; 2679 2680 process_map_.RemoveAllFromProcess(process->GetID()); 2681 BrowserThread::PostTask( 2682 BrowserThread::IO, FROM_HERE, 2683 base::Bind(&ExtensionInfoMap::UnregisterAllExtensionsInProcess, 2684 system_->info_map(), 2685 process->GetID())); 2686 break; 2687 } 2688 case chrome::NOTIFICATION_IMPORT_FINISHED: { 2689 InitAfterImport(); 2690 break; 2691 } 2692 case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: { 2693 extensions::ExtensionHost* host = 2694 content::Details<extensions::ExtensionHost>(details).ptr(); 2695 if (host->extension_host_type() == 2696 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { 2697 std::string extension_id = host->extension_id(); 2698 if (pending_extension_updates_.Contains(extension_id)) { 2699 // We were waiting for this extension to become idle, it now did, so 2700 // finish installation. 2701 MessageLoop::current()->PostDelayedTask( 2702 FROM_HERE, 2703 base::Bind(&ExtensionService::MaybeFinishInstallation, 2704 AsWeakPtr(), extension_id), 2705 base::TimeDelta::FromSeconds(kUpdateIdleDelay)); 2706 } 2707 } 2708 break; 2709 } 2710 2711 default: 2712 NOTREACHED() << "Unexpected notification type."; 2713 } 2714} 2715 2716void ExtensionService::OnPreferenceChanged(PrefServiceBase* service, 2717 const std::string& pref_name) { 2718 DCHECK(pref_name == prefs::kExtensionInstallAllowList || 2719 pref_name == prefs::kExtensionInstallDenyList) 2720 << "Unexpected preference name " << pref_name; 2721 IdentifyAlertableExtensions(); 2722 CheckManagementPolicy(); 2723} 2724 2725bool ExtensionService::HasApps() const { 2726 return !GetAppIds().empty(); 2727} 2728 2729ExtensionIdSet ExtensionService::GetAppIds() const { 2730 ExtensionIdSet result; 2731 for (ExtensionSet::const_iterator it = extensions_.begin(); 2732 it != extensions_.end(); ++it) { 2733 if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT) 2734 result.insert((*it)->id()); 2735 } 2736 2737 return result; 2738} 2739 2740bool ExtensionService::IsBackgroundPageReady(const Extension* extension) const { 2741 if (!extension->has_persistent_background_page()) 2742 return true; 2743 ExtensionRuntimeDataMap::const_iterator it = 2744 extension_runtime_data_.find(extension->id()); 2745 return it == extension_runtime_data_.end() ? false : 2746 it->second.background_page_ready; 2747} 2748 2749void ExtensionService::SetBackgroundPageReady(const Extension* extension) { 2750 DCHECK(extension->has_background_page()); 2751 extension_runtime_data_[extension->id()].background_page_ready = true; 2752 content::NotificationService::current()->Notify( 2753 chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, 2754 content::Source<const Extension>(extension), 2755 content::NotificationService::NoDetails()); 2756} 2757 2758void ExtensionService::InspectBackgroundPage(const Extension* extension) { 2759 DCHECK(extension); 2760 2761 ExtensionProcessManager* pm = 2762 extensions::ExtensionSystem::Get(profile_)->process_manager(); 2763 extensions::LazyBackgroundTaskQueue* queue = 2764 extensions::ExtensionSystem::Get(profile_)->lazy_background_task_queue(); 2765 2766 extensions::ExtensionHost* host = 2767 pm->GetBackgroundHostForExtension(extension->id()); 2768 if (host) { 2769 InspectExtensionHost(host); 2770 } else { 2771 queue->AddPendingTask( 2772 profile_, extension->id(), 2773 base::Bind(&ExtensionService::InspectExtensionHost, 2774 base::Unretained(this))); 2775 } 2776} 2777 2778bool ExtensionService::IsBeingUpgraded(const Extension* extension) const { 2779 ExtensionRuntimeDataMap::const_iterator it = 2780 extension_runtime_data_.find(extension->id()); 2781 return it == extension_runtime_data_.end() ? false : 2782 it->second.being_upgraded; 2783} 2784 2785void ExtensionService::SetBeingUpgraded(const Extension* extension, 2786 bool value) { 2787 extension_runtime_data_[extension->id()].being_upgraded = value; 2788} 2789 2790bool ExtensionService::HasUsedWebRequest(const Extension* extension) const { 2791 ExtensionRuntimeDataMap::const_iterator it = 2792 extension_runtime_data_.find(extension->id()); 2793 return it == extension_runtime_data_.end() ? false : 2794 it->second.has_used_webrequest; 2795} 2796 2797void ExtensionService::SetHasUsedWebRequest(const Extension* extension, 2798 bool value) { 2799 extension_runtime_data_[extension->id()].has_used_webrequest = value; 2800} 2801 2802void ExtensionService::RegisterNaClModule(const GURL& url, 2803 const std::string& mime_type) { 2804 NaClModuleInfo info; 2805 info.url = url; 2806 info.mime_type = mime_type; 2807 2808 DCHECK(FindNaClModule(url) == nacl_module_list_.end()); 2809 nacl_module_list_.push_front(info); 2810} 2811 2812void ExtensionService::UnregisterNaClModule(const GURL& url) { 2813 NaClModuleInfoList::iterator iter = FindNaClModule(url); 2814 DCHECK(iter != nacl_module_list_.end()); 2815 nacl_module_list_.erase(iter); 2816} 2817 2818void ExtensionService::UpdatePluginListWithNaClModules() { 2819 // An extension has been added which has a nacl_module component, which means 2820 // there is a MIME type that module wants to handle, so we need to add that 2821 // MIME type to plugins which handle NaCl modules in order to allow the 2822 // individual modules to handle these types. 2823 FilePath path; 2824 if (!PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) 2825 return; 2826 const content::PepperPluginInfo* pepper_info = 2827 PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path); 2828 if (!pepper_info) 2829 return; 2830 2831 std::vector<webkit::WebPluginMimeType>::const_iterator mime_iter; 2832 // Check each MIME type the plugins handle for the NaCl MIME type. 2833 for (mime_iter = pepper_info->mime_types.begin(); 2834 mime_iter != pepper_info->mime_types.end(); ++mime_iter) { 2835 if (mime_iter->mime_type == kNaClPluginMimeType) { 2836 // This plugin handles "application/x-nacl". 2837 2838 PluginService::GetInstance()-> 2839 UnregisterInternalPlugin(pepper_info->path); 2840 2841 webkit::WebPluginInfo info = pepper_info->ToWebPluginInfo(); 2842 2843 for (ExtensionService::NaClModuleInfoList::const_iterator iter = 2844 nacl_module_list_.begin(); 2845 iter != nacl_module_list_.end(); ++iter) { 2846 // Add the MIME type specified in the extension to this NaCl plugin, 2847 // With an extra "nacl" argument to specify the location of the NaCl 2848 // manifest file. 2849 webkit::WebPluginMimeType mime_type_info; 2850 mime_type_info.mime_type = iter->mime_type; 2851 mime_type_info.additional_param_names.push_back(UTF8ToUTF16("nacl")); 2852 mime_type_info.additional_param_values.push_back( 2853 UTF8ToUTF16(iter->url.spec())); 2854 info.mime_types.push_back(mime_type_info); 2855 } 2856 2857 PluginService::GetInstance()->RefreshPlugins(); 2858 PluginService::GetInstance()->RegisterInternalPlugin(info, true); 2859 // This plugin has been modified, no need to check the rest of its 2860 // types, but continue checking other plugins. 2861 break; 2862 } 2863 } 2864} 2865 2866ExtensionService::NaClModuleInfoList::iterator 2867 ExtensionService::FindNaClModule(const GURL& url) { 2868 for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin(); 2869 iter != nacl_module_list_.end(); ++iter) { 2870 if (iter->url == url) 2871 return iter; 2872 } 2873 return nacl_module_list_.end(); 2874} 2875 2876void ExtensionService::DoPostLoadTasks(const Extension* extension) { 2877 std::map<std::string, int>::iterator it = 2878 on_load_events_.find(extension->id()); 2879 if (it == on_load_events_.end()) 2880 return; 2881 2882 int events_to_fire = it->second; 2883 extensions::LazyBackgroundTaskQueue* queue = 2884 system_->lazy_background_task_queue(); 2885 if (queue->ShouldEnqueueTask(profile(), extension)) { 2886 if (events_to_fire & EVENT_LAUNCHED) 2887 queue->AddPendingTask(profile(), extension->id(), 2888 base::Bind(&ExtensionService::LaunchApplication)); 2889 if (events_to_fire & EVENT_RESTARTED) 2890 queue->AddPendingTask(profile(), extension->id(), 2891 base::Bind(&ExtensionService::RestartApplication)); 2892 } 2893 2894 on_load_events_.erase(it); 2895} 2896 2897// static 2898void ExtensionService::LaunchApplication( 2899 extensions::ExtensionHost* extension_host) { 2900 if (!extension_host) 2901 return; 2902 2903#if !defined(OS_ANDROID) 2904 extensions::LaunchPlatformApp(extension_host->profile(), 2905 extension_host->extension(), 2906 NULL, FilePath()); 2907#endif 2908} 2909 2910// static 2911void ExtensionService::RestartApplication( 2912 extensions::ExtensionHost* extension_host) { 2913 if (!extension_host) 2914 return; 2915 2916#if !defined(OS_ANDROID) 2917 extensions::AppEventRouter::DispatchOnRestartedEvent( 2918 extension_host->profile(), extension_host->extension()); 2919#endif 2920} 2921 2922bool ExtensionService::HasShellWindows(const std::string& extension_id) { 2923 const Extension* current_extension = GetExtensionById(extension_id, false); 2924 return current_extension && current_extension->is_platform_app() && 2925 !extensions::ShellWindowRegistry::Get(profile_)-> 2926 GetShellWindowsForApp(extension_id).empty(); 2927} 2928 2929void ExtensionService::InspectExtensionHost( 2930 extensions::ExtensionHost* host) { 2931 if (host) 2932 DevToolsWindow::OpenDevToolsWindow(host->render_view_host()); 2933} 2934 2935bool ExtensionService::ShouldEnableOnInstall(const Extension* extension) { 2936 // Extensions installed by policy can't be disabled. So even if a previous 2937 // installation disabled the extension, make sure it is now enabled. 2938 if (system_->management_policy()->MustRemainEnabled(extension, NULL)) 2939 return true; 2940 2941 if (extension_prefs_->IsExtensionDisabled(extension->id())) 2942 return false; 2943 2944 if (FeatureSwitch::prompt_for_external_extensions()->IsEnabled()) { 2945 // External extensions are initially disabled. We prompt the user before 2946 // enabling them. 2947 if (Extension::IsExternalLocation(extension->location()) && 2948 !extension_prefs_->IsExternalExtensionAcknowledged(extension->id())) { 2949 return false; 2950 } 2951 } 2952 2953 return true; 2954} 2955 2956bool ExtensionService::IsExtensionIdle(const std::string& extension_id) const { 2957 ExtensionProcessManager* pm = system_->process_manager(); 2958 extensions::ExtensionHost* host = 2959 pm->GetBackgroundHostForExtension(extension_id); 2960 return !host; 2961} 2962