extension_settings_handler.cc revision 923bd855a3a49144a9f75d8a8200416a52bae775
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/ui/webui/extensions/extension_settings_handler.h" 6 7#include "apps/app_load_service.h" 8#include "apps/app_restore_service.h" 9#include "apps/saved_files_service.h" 10#include "apps/shell_window.h" 11#include "apps/shell_window_registry.h" 12#include "base/auto_reset.h" 13#include "base/base64.h" 14#include "base/bind.h" 15#include "base/bind_helpers.h" 16#include "base/command_line.h" 17#include "base/location.h" 18#include "base/message_loop/message_loop.h" 19#include "base/metrics/histogram.h" 20#include "base/prefs/pref_service.h" 21#include "base/strings/string_number_conversions.h" 22#include "base/strings/string_util.h" 23#include "base/strings/utf_string_conversions.h" 24#include "base/values.h" 25#include "base/version.h" 26#include "chrome/browser/browser_process.h" 27#include "chrome/browser/chrome_notification_types.h" 28#include "chrome/browser/devtools/devtools_window.h" 29#include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 30#include "chrome/browser/extensions/component_loader.h" 31#include "chrome/browser/extensions/crx_installer.h" 32#include "chrome/browser/extensions/devtools_util.h" 33#include "chrome/browser/extensions/error_console/error_console.h" 34#include "chrome/browser/extensions/extension_action_manager.h" 35#include "chrome/browser/extensions/extension_disabled_ui.h" 36#include "chrome/browser/extensions/extension_error_reporter.h" 37#include "chrome/browser/extensions/extension_host.h" 38#include "chrome/browser/extensions/extension_service.h" 39#include "chrome/browser/extensions/extension_system.h" 40#include "chrome/browser/extensions/extension_tab_util.h" 41#include "chrome/browser/extensions/extension_util.h" 42#include "chrome/browser/extensions/extension_warning_set.h" 43#include "chrome/browser/extensions/unpacked_installer.h" 44#include "chrome/browser/extensions/updater/extension_updater.h" 45#include "chrome/browser/google/google_util.h" 46#include "chrome/browser/managed_mode/managed_user_service.h" 47#include "chrome/browser/managed_mode/managed_user_service_factory.h" 48#include "chrome/browser/profiles/profile.h" 49#include "chrome/browser/tab_contents/background_contents.h" 50#include "chrome/browser/ui/browser_finder.h" 51#include "chrome/browser/ui/chrome_select_file_policy.h" 52#include "chrome/browser/ui/extensions/application_launch.h" 53#include "chrome/browser/ui/webui/extensions/extension_basic_info.h" 54#include "chrome/browser/ui/webui/extensions/extension_icon_source.h" 55#include "chrome/common/chrome_switches.h" 56#include "chrome/common/extensions/extension_constants.h" 57#include "chrome/common/extensions/extension_icon_set.h" 58#include "chrome/common/extensions/extension_set.h" 59#include "chrome/common/extensions/manifest_url_handler.h" 60#include "chrome/common/pref_names.h" 61#include "chrome/common/url_constants.h" 62#include "components/user_prefs/pref_registry_syncable.h" 63#include "content/public/browser/notification_service.h" 64#include "content/public/browser/notification_source.h" 65#include "content/public/browser/notification_types.h" 66#include "content/public/browser/render_process_host.h" 67#include "content/public/browser/render_view_host.h" 68#include "content/public/browser/site_instance.h" 69#include "content/public/browser/user_metrics.h" 70#include "content/public/browser/web_contents.h" 71#include "content/public/browser/web_contents_view.h" 72#include "content/public/browser/web_ui.h" 73#include "content/public/browser/web_ui_data_source.h" 74#include "extensions/browser/extension_error.h" 75#include "extensions/browser/lazy_background_task_queue.h" 76#include "extensions/browser/management_policy.h" 77#include "extensions/browser/view_type_utils.h" 78#include "extensions/common/constants.h" 79#include "extensions/common/extension.h" 80#include "extensions/common/feature_switch.h" 81#include "extensions/common/manifest_handlers/background_info.h" 82#include "extensions/common/manifest_handlers/incognito_info.h" 83#include "grit/browser_resources.h" 84#include "grit/chromium_strings.h" 85#include "grit/generated_resources.h" 86#include "grit/theme_resources.h" 87#include "ui/base/l10n/l10n_util.h" 88#include "ui/base/resource/resource_bundle.h" 89 90using base::DictionaryValue; 91using base::ListValue; 92using content::RenderViewHost; 93using content::WebContents; 94 95namespace extensions { 96 97ExtensionPage::ExtensionPage(const GURL& url, 98 int render_process_id, 99 int render_view_id, 100 bool incognito, 101 bool generated_background_page) 102 : url(url), 103 render_process_id(render_process_id), 104 render_view_id(render_view_id), 105 incognito(incognito), 106 generated_background_page(generated_background_page) { 107} 108 109// On Mac, the install prompt is not modal. This means that the user can 110// navigate while the dialog is up, causing the dialog handler to outlive the 111// ExtensionSettingsHandler. That's a problem because the dialog framework will 112// try to contact us back once the dialog is closed, which causes a crash. 113// This class is designed to broker the message between the two objects, while 114// managing its own lifetime so that it can outlive the ExtensionSettingsHandler 115// and (when doing so) gracefully ignore the message from the dialog. 116class BrokerDelegate : public ExtensionInstallPrompt::Delegate { 117 public: 118 explicit BrokerDelegate( 119 const base::WeakPtr<ExtensionSettingsHandler>& delegate) 120 : delegate_(delegate) {} 121 122 // ExtensionInstallPrompt::Delegate implementation. 123 virtual void InstallUIProceed() OVERRIDE { 124 if (delegate_) 125 delegate_->InstallUIProceed(); 126 delete this; 127 }; 128 129 virtual void InstallUIAbort(bool user_initiated) OVERRIDE { 130 if (delegate_) 131 delegate_->InstallUIAbort(user_initiated); 132 delete this; 133 }; 134 135 private: 136 base::WeakPtr<ExtensionSettingsHandler> delegate_; 137 138 DISALLOW_COPY_AND_ASSIGN(BrokerDelegate); 139}; 140 141/////////////////////////////////////////////////////////////////////////////// 142// 143// ExtensionSettingsHandler 144// 145/////////////////////////////////////////////////////////////////////////////// 146 147ExtensionSettingsHandler::ExtensionSettingsHandler() 148 : extension_service_(NULL), 149 management_policy_(NULL), 150 ignore_notifications_(false), 151 deleting_rvh_(NULL), 152 deleting_rwh_id_(-1), 153 deleting_rph_id_(-1), 154 registered_for_notifications_(false), 155 warning_service_observer_(this), 156 error_console_observer_(this), 157 should_do_verification_check_(false) { 158} 159 160ExtensionSettingsHandler::~ExtensionSettingsHandler() { 161 // There may be pending file dialogs, we need to tell them that we've gone 162 // away so they don't try and call back to us. 163 if (load_extension_dialog_.get()) 164 load_extension_dialog_->ListenerDestroyed(); 165} 166 167ExtensionSettingsHandler::ExtensionSettingsHandler(ExtensionService* service, 168 ManagementPolicy* policy) 169 : extension_service_(service), 170 management_policy_(policy), 171 ignore_notifications_(false), 172 deleting_rvh_(NULL), 173 deleting_rwh_id_(-1), 174 deleting_rph_id_(-1), 175 registered_for_notifications_(false), 176 warning_service_observer_(this), 177 error_console_observer_(this), 178 should_do_verification_check_(false) { 179} 180 181// static 182void ExtensionSettingsHandler::RegisterProfilePrefs( 183 user_prefs::PrefRegistrySyncable* registry) { 184 registry->RegisterBooleanPref( 185 prefs::kExtensionsUIDeveloperMode, 186 false, 187 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 188} 189 190base::DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue( 191 const Extension* extension, 192 const std::vector<ExtensionPage>& pages, 193 const ExtensionWarningService* warning_service) { 194 base::DictionaryValue* extension_data = new base::DictionaryValue(); 195 bool enabled = extension_service_->IsExtensionEnabled(extension->id()); 196 GetExtensionBasicInfo(extension, enabled, extension_data); 197 198 ExtensionPrefs* prefs = extension_service_->extension_prefs(); 199 int disable_reasons = prefs->GetDisableReasons(extension->id()); 200 201 bool suspicious_install = 202 (disable_reasons & Extension::DISABLE_NOT_VERIFIED) != 0; 203 extension_data->SetBoolean("suspiciousInstall", suspicious_install); 204 if (suspicious_install) 205 should_do_verification_check_ = true; 206 207 bool managed_install = 208 !management_policy_->UserMayModifySettings(extension, NULL); 209 extension_data->SetBoolean("managedInstall", managed_install); 210 211 // We should not get into a state where both are true. 212 DCHECK(managed_install == false || suspicious_install == false); 213 214 GURL icon = 215 ExtensionIconSource::GetIconURL(extension, 216 extension_misc::EXTENSION_ICON_MEDIUM, 217 ExtensionIconSet::MATCH_BIGGER, 218 !enabled, NULL); 219 if (Manifest::IsUnpackedLocation(extension->location())) 220 extension_data->SetString("path", extension->path().value()); 221 extension_data->SetString("icon", icon.spec()); 222 extension_data->SetBoolean("isUnpacked", 223 Manifest::IsUnpackedLocation(extension->location())); 224 extension_data->SetBoolean("terminated", 225 extension_service_->terminated_extensions()->Contains(extension->id())); 226 extension_data->SetBoolean("enabledIncognito", 227 extension_util::IsIncognitoEnabled(extension->id(), extension_service_)); 228 extension_data->SetBoolean("incognitoCanBeToggled", 229 extension->can_be_incognito_enabled() && 230 !extension->force_incognito_enabled()); 231 extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access()); 232 extension_data->SetBoolean("allowFileAccess", 233 extension_util::AllowFileAccess(extension, extension_service_)); 234 extension_data->SetBoolean("allow_reload", 235 Manifest::IsUnpackedLocation(extension->location())); 236 extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app()); 237 extension_data->SetBoolean("is_platform_app", extension->is_platform_app()); 238 extension_data->SetBoolean("homepageProvided", 239 ManifestURL::GetHomepageURL(extension).is_valid()); 240 241 base::string16 location_text; 242 if (Manifest::IsPolicyLocation(extension->location())) { 243 location_text = l10n_util::GetStringUTF16( 244 IDS_OPTIONS_INSTALL_LOCATION_ENTERPRISE); 245 } else if (extension->location() == Manifest::INTERNAL && 246 !ManifestURL::UpdatesFromGallery(extension)) { 247 location_text = l10n_util::GetStringUTF16( 248 IDS_OPTIONS_INSTALL_LOCATION_UNKNOWN); 249 } else if (extension->location() == Manifest::EXTERNAL_REGISTRY) { 250 location_text = l10n_util::GetStringUTF16( 251 IDS_OPTIONS_INSTALL_LOCATION_3RD_PARTY); 252 } 253 extension_data->SetString("locationText", location_text); 254 255 // Force unpacked extensions to show at the top. 256 if (Manifest::IsUnpackedLocation(extension->location())) 257 extension_data->SetInteger("order", 1); 258 else 259 extension_data->SetInteger("order", 2); 260 261 if (!ExtensionActionAPI::GetBrowserActionVisibility( 262 extension_service_->extension_prefs(), extension->id())) { 263 extension_data->SetBoolean("enable_show_button", true); 264 } 265 266 // Add views 267 base::ListValue* views = new base::ListValue; 268 for (std::vector<ExtensionPage>::const_iterator iter = pages.begin(); 269 iter != pages.end(); ++iter) { 270 base::DictionaryValue* view_value = new base::DictionaryValue; 271 if (iter->url.scheme() == kExtensionScheme) { 272 // No leading slash. 273 view_value->SetString("path", iter->url.path().substr(1)); 274 } else { 275 // For live pages, use the full URL. 276 view_value->SetString("path", iter->url.spec()); 277 } 278 view_value->SetInteger("renderViewId", iter->render_view_id); 279 view_value->SetInteger("renderProcessId", iter->render_process_id); 280 view_value->SetBoolean("incognito", iter->incognito); 281 view_value->SetBoolean("generatedBackgroundPage", 282 iter->generated_background_page); 283 views->Append(view_value); 284 } 285 extension_data->Set("views", views); 286 ExtensionActionManager* extension_action_manager = 287 ExtensionActionManager::Get(extension_service_->profile()); 288 extension_data->SetBoolean( 289 "hasPopupAction", 290 extension_action_manager->GetBrowserAction(*extension) || 291 extension_action_manager->GetPageAction(*extension)); 292 293 // Add warnings. 294 if (warning_service) { 295 std::vector<std::string> warnings = 296 warning_service->GetWarningMessagesForExtension(extension->id()); 297 298 if (!warnings.empty()) { 299 base::ListValue* warnings_list = new base::ListValue; 300 for (std::vector<std::string>::const_iterator iter = warnings.begin(); 301 iter != warnings.end(); ++iter) { 302 warnings_list->Append(base::Value::CreateStringValue(*iter)); 303 } 304 extension_data->Set("warnings", warnings_list); 305 } 306 } 307 308 // If the ErrorConsole is enabled, get the errors for the extension and add 309 // them to the list. Otherwise, use the install warnings (using both is 310 // redundant). 311 ErrorConsole* error_console = 312 ErrorConsole::Get(extension_service_->profile()); 313 if (error_console->enabled()) { 314 const ErrorConsole::ErrorList& errors = 315 error_console->GetErrorsForExtension(extension->id()); 316 if (!errors.empty()) { 317 scoped_ptr<ListValue> manifest_errors(new ListValue); 318 scoped_ptr<ListValue> runtime_errors(new ListValue); 319 for (ErrorConsole::ErrorList::const_iterator iter = errors.begin(); 320 iter != errors.end(); ++iter) { 321 if ((*iter)->type() == ExtensionError::MANIFEST_ERROR) { 322 manifest_errors->Append((*iter)->ToValue().release()); 323 } else { // Handle runtime error. 324 const RuntimeError* error = static_cast<const RuntimeError*>(*iter); 325 scoped_ptr<DictionaryValue> value = error->ToValue(); 326 bool can_inspect = 327 !(deleting_rwh_id_ == error->render_view_id() && 328 deleting_rph_id_ == error->render_process_id()) && 329 RenderViewHost::FromID(error->render_process_id(), 330 error->render_view_id()) != NULL; 331 value->SetBoolean("canInspect", can_inspect); 332 runtime_errors->Append(value.release()); 333 } 334 } 335 if (!manifest_errors->empty()) 336 extension_data->Set("manifestErrors", manifest_errors.release()); 337 if (!runtime_errors->empty()) 338 extension_data->Set("runtimeErrors", runtime_errors.release()); 339 } 340 } else if (Manifest::IsUnpackedLocation(extension->location())) { 341 const std::vector<InstallWarning>& install_warnings = 342 extension->install_warnings(); 343 if (!install_warnings.empty()) { 344 scoped_ptr<base::ListValue> list(new base::ListValue()); 345 for (std::vector<InstallWarning>::const_iterator it = 346 install_warnings.begin(); it != install_warnings.end(); ++it) { 347 base::DictionaryValue* item = new base::DictionaryValue(); 348 item->SetString("message", it->message); 349 list->Append(item); 350 } 351 extension_data->Set("installWarnings", list.release()); 352 } 353 } 354 355 return extension_data; 356} 357 358void ExtensionSettingsHandler::GetLocalizedValues( 359 content::WebUIDataSource* source) { 360 source->AddString("extensionSettings", 361 l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE)); 362 363 source->AddString("extensionSettingsDeveloperMode", 364 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK)); 365 source->AddString("extensionSettingsNoExtensions", 366 l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED)); 367 source->AddString("extensionSettingsSuggestGallery", 368 l10n_util::GetStringFUTF16(IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY, 369 ASCIIToUTF16(google_util::AppendGoogleLocaleParam( 370 GURL(extension_urls::GetExtensionGalleryURL())).spec()))); 371 source->AddString("extensionSettingsGetMoreExtensions", 372 l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS)); 373 source->AddString("extensionSettingsGetMoreExtensionsUrl", 374 ASCIIToUTF16(google_util::AppendGoogleLocaleParam( 375 GURL(extension_urls::GetExtensionGalleryURL())).spec())); 376 source->AddString("extensionSettingsExtensionId", 377 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID)); 378 source->AddString("extensionSettingsExtensionPath", 379 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PATH)); 380 source->AddString("extensionSettingsInspectViews", 381 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS)); 382 source->AddString("extensionSettingsInstallWarnings", 383 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALL_WARNINGS)); 384 source->AddString("viewIncognito", 385 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO)); 386 source->AddString("viewInactive", 387 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INACTIVE)); 388 source->AddString("backgroundPage", 389 l10n_util::GetStringUTF16(IDS_EXTENSIONS_BACKGROUND_PAGE)); 390 source->AddString("extensionSettingsEnable", 391 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE)); 392 source->AddString("extensionSettingsEnabled", 393 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLED)); 394 source->AddString("extensionSettingsRemove", 395 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REMOVE)); 396 source->AddString("extensionSettingsEnableIncognito", 397 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO)); 398 source->AddString("extensionSettingsAllowFileAccess", 399 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS)); 400 source->AddString("extensionSettingsIncognitoWarning", 401 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING)); 402 source->AddString("extensionSettingsReloadTerminated", 403 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_TERMINATED)); 404 source->AddString("extensionSettingsLaunch", 405 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LAUNCH)); 406 source->AddString("extensionSettingsReloadUnpacked", 407 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_UNPACKED)); 408 source->AddString("extensionSettingsOptions", 409 l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS_LINK)); 410 source->AddString("extensionSettingsPermissions", 411 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PERMISSIONS_LINK)); 412 source->AddString("extensionSettingsVisitWebsite", 413 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSITE)); 414 source->AddString("extensionSettingsVisitWebStore", 415 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSTORE)); 416 source->AddString("extensionSettingsPolicyControlled", 417 l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED)); 418 source->AddString("extensionSettingsManagedMode", 419 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_MANAGED_USER)); 420 source->AddString("extensionSettingsSuspiciousInstall", 421 l10n_util::GetStringFUTF16( 422 IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE, 423 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE))); 424 source->AddString("extensionSettingsSuspiciousInstallLearnMore", 425 l10n_util::GetStringUTF16(IDS_LEARN_MORE)); 426 source->AddString("extensionSettingsSuspiciousInstallHelpUrl", 427 ASCIIToUTF16(google_util::AppendGoogleLocaleParam( 428 GURL(chrome::kRemoveNonCWSExtensionURL)).spec())); 429 source->AddString("extensionSettingsUseAppsDevTools", 430 l10n_util::GetStringUTF16(IDS_EXTENSIONS_USE_APPS_DEV_TOOLS)); 431 source->AddString("extensionSettingsOpenAppsDevTools", 432 l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPEN_APPS_DEV_TOOLS)); 433 source->AddString("extensionSettingsShowButton", 434 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON)); 435 source->AddString("extensionSettingsLoadUnpackedButton", 436 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON)); 437 source->AddString("extensionSettingsPackButton", 438 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON)); 439 source->AddString("extensionSettingsCommandsLink", 440 l10n_util::GetStringUTF16(IDS_EXTENSIONS_COMMANDS_CONFIGURE)); 441 source->AddString("extensionSettingsUpdateButton", 442 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON)); 443 source->AddString("extensionSettingsCrashMessage", 444 l10n_util::GetStringUTF16(IDS_EXTENSIONS_CRASHED_EXTENSION)); 445 source->AddString("extensionSettingsInDevelopment", 446 l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT)); 447 source->AddString("extensionSettingsWarningsTitle", 448 l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_TITLE)); 449 source->AddString("extensionSettingsShowDetails", 450 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS)); 451 source->AddString("extensionSettingsHideDetails", 452 l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS)); 453 454 // TODO(estade): comb through the above strings to find ones no longer used in 455 // uber extensions. 456 source->AddString("extensionUninstall", 457 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL)); 458} 459 460void ExtensionSettingsHandler::RenderViewDeleted( 461 RenderViewHost* render_view_host) { 462 deleting_rvh_ = render_view_host; 463 Profile* source_profile = Profile::FromBrowserContext( 464 render_view_host->GetSiteInstance()->GetBrowserContext()); 465 if (!Profile::FromWebUI(web_ui())->IsSameProfile(source_profile)) 466 return; 467 MaybeUpdateAfterNotification(); 468} 469 470void ExtensionSettingsHandler::DidStartNavigationToPendingEntry( 471 const GURL& url, 472 content::NavigationController::ReloadType reload_type) { 473 if (reload_type != content::NavigationController::NO_RELOAD) 474 ReloadUnpackedExtensions(); 475} 476 477void ExtensionSettingsHandler::RegisterMessages() { 478 // Don't override an |extension_service_| or |management_policy_| injected 479 // for testing. 480 if (!extension_service_) { 481 extension_service_ = Profile::FromWebUI(web_ui())->GetOriginalProfile()-> 482 GetExtensionService(); 483 } 484 if (!management_policy_) { 485 management_policy_ = ExtensionSystem::Get( 486 extension_service_->profile())->management_policy(); 487 } 488 489 web_ui()->RegisterMessageCallback("extensionSettingsRequestExtensionsData", 490 base::Bind(&ExtensionSettingsHandler::HandleRequestExtensionsData, 491 AsWeakPtr())); 492 web_ui()->RegisterMessageCallback("extensionSettingsToggleDeveloperMode", 493 base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode, 494 AsWeakPtr())); 495 web_ui()->RegisterMessageCallback("extensionSettingsInspect", 496 base::Bind(&ExtensionSettingsHandler::HandleInspectMessage, 497 AsWeakPtr())); 498 web_ui()->RegisterMessageCallback("extensionSettingsLaunch", 499 base::Bind(&ExtensionSettingsHandler::HandleLaunchMessage, 500 AsWeakPtr())); 501 web_ui()->RegisterMessageCallback("extensionSettingsReload", 502 base::Bind(&ExtensionSettingsHandler::HandleReloadMessage, 503 AsWeakPtr())); 504 web_ui()->RegisterMessageCallback("extensionSettingsEnable", 505 base::Bind(&ExtensionSettingsHandler::HandleEnableMessage, 506 AsWeakPtr())); 507 web_ui()->RegisterMessageCallback("extensionSettingsEnableIncognito", 508 base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage, 509 AsWeakPtr())); 510 web_ui()->RegisterMessageCallback("extensionSettingsAllowFileAccess", 511 base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage, 512 AsWeakPtr())); 513 web_ui()->RegisterMessageCallback("extensionSettingsUninstall", 514 base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage, 515 AsWeakPtr())); 516 web_ui()->RegisterMessageCallback("extensionSettingsOptions", 517 base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage, 518 AsWeakPtr())); 519 web_ui()->RegisterMessageCallback("extensionSettingsPermissions", 520 base::Bind(&ExtensionSettingsHandler::HandlePermissionsMessage, 521 AsWeakPtr())); 522 web_ui()->RegisterMessageCallback("extensionSettingsShowButton", 523 base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage, 524 AsWeakPtr())); 525 web_ui()->RegisterMessageCallback("extensionSettingsAutoupdate", 526 base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage, 527 AsWeakPtr())); 528 web_ui()->RegisterMessageCallback("extensionSettingsLoadUnpackedExtension", 529 base::Bind(&ExtensionSettingsHandler::HandleLoadUnpackedExtensionMessage, 530 AsWeakPtr())); 531} 532 533void ExtensionSettingsHandler::FileSelected(const base::FilePath& path, 534 int index, 535 void* params) { 536 last_unpacked_directory_ = base::FilePath(path); 537 UnpackedInstaller::Create(extension_service_)->Load(path); 538} 539 540void ExtensionSettingsHandler::MultiFilesSelected( 541 const std::vector<base::FilePath>& files, void* params) { 542 NOTREACHED(); 543} 544 545void ExtensionSettingsHandler::FileSelectionCanceled(void* params) { 546} 547 548void ExtensionSettingsHandler::OnErrorAdded(const ExtensionError* error) { 549 MaybeUpdateAfterNotification(); 550} 551 552void ExtensionSettingsHandler::Observe( 553 int type, 554 const content::NotificationSource& source, 555 const content::NotificationDetails& details) { 556 Profile* profile = Profile::FromWebUI(web_ui()); 557 Profile* source_profile = NULL; 558 switch (type) { 559 // We listen for notifications that will result in the page being 560 // repopulated with data twice for the same event in certain cases. 561 // For instance, EXTENSION_LOADED & EXTENSION_HOST_CREATED because 562 // we don't know about the views for an extension at EXTENSION_LOADED, but 563 // if we only listen to EXTENSION_HOST_CREATED, we'll miss extensions 564 // that don't have a process at startup. 565 // 566 // Doing it this way gets everything but causes the page to be rendered 567 // more than we need. It doesn't seem to result in any noticeable flicker. 568 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: 569 deleting_rvh_ = content::Details<BackgroundContents>(details)-> 570 web_contents()->GetRenderViewHost(); 571 // Fall through. 572 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED: 573 case chrome::NOTIFICATION_EXTENSION_HOST_CREATED: 574 source_profile = content::Source<Profile>(source).ptr(); 575 if (!profile->IsSameProfile(source_profile)) 576 return; 577 MaybeUpdateAfterNotification(); 578 break; 579 case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: { 580 content::RenderWidgetHost* rwh = 581 content::Source<content::RenderWidgetHost>(source).ptr(); 582 deleting_rwh_id_ = rwh->GetRoutingID(); 583 deleting_rph_id_ = rwh->GetProcess()->GetID(); 584 MaybeUpdateAfterNotification(); 585 break; 586 } 587 case chrome::NOTIFICATION_EXTENSION_LOADED: 588 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 589 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: 590 case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED: 591 case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED: 592 MaybeUpdateAfterNotification(); 593 break; 594 case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: 595 // This notification is sent when the extension host destruction begins, 596 // not when it finishes. We use PostTask to delay the update until after 597 // the destruction finishes. 598 base::MessageLoop::current()->PostTask( 599 FROM_HERE, 600 base::Bind(&ExtensionSettingsHandler::MaybeUpdateAfterNotification, 601 AsWeakPtr())); 602 break; 603 default: 604 NOTREACHED(); 605 } 606} 607 608void ExtensionSettingsHandler::ExtensionUninstallAccepted() { 609 DCHECK(!extension_id_prompting_.empty()); 610 611 bool was_terminated = false; 612 613 // The extension can be uninstalled in another window while the UI was 614 // showing. Do nothing in that case. 615 const Extension* extension = 616 extension_service_->GetExtensionById(extension_id_prompting_, true); 617 if (!extension) { 618 extension = extension_service_->GetTerminatedExtension( 619 extension_id_prompting_); 620 was_terminated = true; 621 } 622 if (!extension) 623 return; 624 625 extension_service_->UninstallExtension(extension_id_prompting_, 626 false, // External uninstall. 627 NULL); // Error. 628 extension_id_prompting_ = ""; 629 630 // There will be no EXTENSION_UNLOADED notification for terminated 631 // extensions as they were already unloaded. 632 if (was_terminated) 633 HandleRequestExtensionsData(NULL); 634} 635 636void ExtensionSettingsHandler::ExtensionUninstallCanceled() { 637 extension_id_prompting_ = ""; 638} 639 640void ExtensionSettingsHandler::ExtensionWarningsChanged() { 641 MaybeUpdateAfterNotification(); 642} 643 644// This is called when the user clicks "Revoke File Access." 645void ExtensionSettingsHandler::InstallUIProceed() { 646 Profile* profile = Profile::FromWebUI(web_ui()); 647 apps::SavedFilesService::Get(profile)->ClearQueue( 648 extension_service_->GetExtensionById(extension_id_prompting_, true)); 649 if (apps::AppRestoreService::Get(profile)-> 650 IsAppRestorable(extension_id_prompting_)) { 651 apps::AppLoadService::Get(profile)->RestartApplication( 652 extension_id_prompting_); 653 } 654 extension_id_prompting_.clear(); 655} 656 657void ExtensionSettingsHandler::InstallUIAbort(bool user_initiated) { 658 extension_id_prompting_.clear(); 659} 660 661void ExtensionSettingsHandler::ReloadUnpackedExtensions() { 662 const ExtensionSet* extensions = extension_service_->extensions(); 663 std::vector<const Extension*> unpacked_extensions; 664 for (ExtensionSet::const_iterator extension = extensions->begin(); 665 extension != extensions->end(); ++extension) { 666 if (Manifest::IsUnpackedLocation((*extension)->location())) 667 unpacked_extensions.push_back(extension->get()); 668 } 669 670 for (std::vector<const Extension*>::iterator iter = 671 unpacked_extensions.begin(); iter != unpacked_extensions.end(); ++iter) { 672 extension_service_->ReloadExtension((*iter)->id()); 673 } 674} 675 676void ExtensionSettingsHandler::HandleRequestExtensionsData( 677 const base::ListValue* args) { 678 base::DictionaryValue results; 679 680 Profile* profile = Profile::FromWebUI(web_ui()); 681 682 // Add the extensions to the results structure. 683 base::ListValue* extensions_list = new base::ListValue(); 684 685 ExtensionWarningService* warnings = 686 ExtensionSystem::Get(profile)->warning_service(); 687 688 const ExtensionSet* extensions = extension_service_->extensions(); 689 for (ExtensionSet::const_iterator extension = extensions->begin(); 690 extension != extensions->end(); ++extension) { 691 if ((*extension)->ShouldDisplayInExtensionSettings()) { 692 extensions_list->Append(CreateExtensionDetailValue( 693 extension->get(), 694 GetInspectablePagesForExtension(extension->get(), true), 695 warnings)); 696 } 697 } 698 extensions = extension_service_->disabled_extensions(); 699 for (ExtensionSet::const_iterator extension = extensions->begin(); 700 extension != extensions->end(); ++extension) { 701 if ((*extension)->ShouldDisplayInExtensionSettings()) { 702 extensions_list->Append(CreateExtensionDetailValue( 703 extension->get(), 704 GetInspectablePagesForExtension(extension->get(), false), 705 warnings)); 706 } 707 } 708 extensions = extension_service_->terminated_extensions(); 709 std::vector<ExtensionPage> empty_pages; 710 for (ExtensionSet::const_iterator extension = extensions->begin(); 711 extension != extensions->end(); ++extension) { 712 if ((*extension)->ShouldDisplayInExtensionSettings()) { 713 extensions_list->Append(CreateExtensionDetailValue( 714 extension->get(), 715 empty_pages, // Terminated process has no active pages. 716 warnings)); 717 } 718 } 719 results.Set("extensions", extensions_list); 720 721 bool is_managed = profile->IsManaged(); 722 bool developer_mode = 723 !is_managed && 724 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); 725 results.SetBoolean("profileIsManaged", is_managed); 726 results.SetBoolean("developerMode", developer_mode); 727 results.SetBoolean( 728 "appsDevToolsEnabled", 729 CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsDevtool)); 730 731 bool load_unpacked_disabled = 732 extension_service_->extension_prefs()->ExtensionsBlacklistedByDefault(); 733 results.SetBoolean("loadUnpackedDisabled", load_unpacked_disabled); 734 735 web_ui()->CallJavascriptFunction( 736 "extensions.ExtensionSettings.returnExtensionsData", results); 737 738 MaybeRegisterForNotifications(); 739 UMA_HISTOGRAM_BOOLEAN("ExtensionSettings.ShouldDoVerificationCheck", 740 should_do_verification_check_); 741 if (should_do_verification_check_) { 742 should_do_verification_check_ = false; 743 extension_service_->VerifyAllExtensions(false); // bootstrap=false. 744 } 745} 746 747void ExtensionSettingsHandler::HandleToggleDeveloperMode( 748 const base::ListValue* args) { 749 Profile* profile = Profile::FromWebUI(web_ui()); 750 if (profile->IsManaged()) 751 return; 752 753 bool developer_mode = 754 !profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); 755 profile->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, 756 developer_mode); 757 758 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsDevtool)) 759 return; 760 761 base::FilePath apps_debugger_path(FILE_PATH_LITERAL("apps_debugger")); 762 if (developer_mode) { 763 profile->GetExtensionService()->component_loader()->Add( 764 IDR_APPS_DEBUGGER_MANIFEST, 765 apps_debugger_path); 766 } else { 767 std::string extension_id = 768 profile->GetExtensionService()->component_loader()->GetExtensionID( 769 IDR_APPS_DEBUGGER_MANIFEST, 770 apps_debugger_path); 771 scoped_refptr<const Extension> extension( 772 profile->GetExtensionService()->GetInstalledExtension(extension_id)); 773 profile->GetExtensionService()->component_loader()->Remove(extension_id); 774 } 775} 776 777void ExtensionSettingsHandler::HandleInspectMessage( 778 const base::ListValue* args) { 779 std::string extension_id; 780 std::string render_process_id_str; 781 std::string render_view_id_str; 782 int render_process_id; 783 int render_view_id; 784 bool incognito; 785 CHECK_EQ(4U, args->GetSize()); 786 CHECK(args->GetString(0, &extension_id)); 787 CHECK(args->GetString(1, &render_process_id_str)); 788 CHECK(args->GetString(2, &render_view_id_str)); 789 CHECK(args->GetBoolean(3, &incognito)); 790 CHECK(base::StringToInt(render_process_id_str, &render_process_id)); 791 CHECK(base::StringToInt(render_view_id_str, &render_view_id)); 792 793 if (render_process_id == -1) { 794 // This message is for a lazy background page. Start the page if necessary. 795 const Extension* extension = 796 extension_service_->extensions()->GetByID(extension_id); 797 DCHECK(extension); 798 devtools_util::InspectBackgroundPage(extension, 799 Profile::FromWebUI(web_ui())); 800 return; 801 } 802 803 RenderViewHost* host = RenderViewHost::FromID(render_process_id, 804 render_view_id); 805 if (!host) { 806 // This can happen if the host has gone away since the page was displayed. 807 return; 808 } 809 810 DevToolsWindow::OpenDevToolsWindow(host); 811} 812 813void ExtensionSettingsHandler::HandleLaunchMessage( 814 const base::ListValue* args) { 815 CHECK_EQ(1U, args->GetSize()); 816 std::string extension_id; 817 CHECK(args->GetString(0, &extension_id)); 818 const Extension* extension = 819 extension_service_->GetExtensionById(extension_id, false); 820 OpenApplication(AppLaunchParams(extension_service_->profile(), extension, 821 extensions::LAUNCH_CONTAINER_WINDOW, 822 NEW_WINDOW)); 823} 824 825void ExtensionSettingsHandler::HandleReloadMessage( 826 const base::ListValue* args) { 827 std::string extension_id = UTF16ToUTF8(ExtractStringValue(args)); 828 CHECK(!extension_id.empty()); 829 extension_service_->ReloadExtension(extension_id); 830} 831 832void ExtensionSettingsHandler::HandleEnableMessage( 833 const base::ListValue* args) { 834 CHECK_EQ(2U, args->GetSize()); 835 std::string extension_id, enable_str; 836 CHECK(args->GetString(0, &extension_id)); 837 CHECK(args->GetString(1, &enable_str)); 838 839 const Extension* extension = 840 extension_service_->GetInstalledExtension(extension_id); 841 if (!extension || 842 !management_policy_->UserMayModifySettings(extension, NULL)) { 843 LOG(ERROR) << "Attempt to enable an extension that is non-usermanagable was" 844 << "made. Extension id: " << extension->id(); 845 return; 846 } 847 848 if (enable_str == "true") { 849 ExtensionPrefs* prefs = extension_service_->extension_prefs(); 850 if (prefs->DidExtensionEscalatePermissions(extension_id)) { 851 ShowExtensionDisabledDialog( 852 extension_service_, web_ui()->GetWebContents(), extension); 853 } else if ((prefs->GetDisableReasons(extension_id) & 854 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) && 855 !requirements_checker_.get()) { 856 // Recheck the requirements. 857 scoped_refptr<const Extension> extension = 858 extension_service_->GetExtensionById(extension_id, 859 true /* include disabled */); 860 requirements_checker_.reset(new RequirementsChecker); 861 requirements_checker_->Check( 862 extension, 863 base::Bind(&ExtensionSettingsHandler::OnRequirementsChecked, 864 AsWeakPtr(), extension_id)); 865 } else { 866 extension_service_->EnableExtension(extension_id); 867 } 868 } else { 869 extension_service_->DisableExtension( 870 extension_id, Extension::DISABLE_USER_ACTION); 871 } 872} 873 874void ExtensionSettingsHandler::HandleEnableIncognitoMessage( 875 const base::ListValue* args) { 876 CHECK_EQ(2U, args->GetSize()); 877 std::string extension_id, enable_str; 878 CHECK(args->GetString(0, &extension_id)); 879 CHECK(args->GetString(1, &enable_str)); 880 const Extension* extension = 881 extension_service_->GetInstalledExtension(extension_id); 882 if (!extension) 883 return; 884 885 // Flipping the incognito bit will generate unload/load notifications for the 886 // extension, but we don't want to reload the page, because a) we've already 887 // updated the UI to reflect the change, and b) we want the yellow warning 888 // text to stay until the user has left the page. 889 // 890 // TODO(aa): This creates crappiness in some cases. For example, in a main 891 // window, when toggling this, the browser action will flicker because it gets 892 // unloaded, then reloaded. It would be better to have a dedicated 893 // notification for this case. 894 // 895 // Bug: http://crbug.com/41384 896 base::AutoReset<bool> auto_reset_ignore_notifications( 897 &ignore_notifications_, true); 898 extension_util::SetIsIncognitoEnabled(extension->id(), 899 extension_service_, 900 enable_str == "true"); 901} 902 903void ExtensionSettingsHandler::HandleAllowFileAccessMessage( 904 const base::ListValue* args) { 905 CHECK_EQ(2U, args->GetSize()); 906 std::string extension_id, allow_str; 907 CHECK(args->GetString(0, &extension_id)); 908 CHECK(args->GetString(1, &allow_str)); 909 const Extension* extension = 910 extension_service_->GetInstalledExtension(extension_id); 911 if (!extension) 912 return; 913 914 if (!management_policy_->UserMayModifySettings(extension, NULL)) { 915 LOG(ERROR) << "Attempt to change allow file access of an extension that is " 916 << "non-usermanagable was made. Extension id : " 917 << extension->id(); 918 return; 919 } 920 921 extension_util::SetAllowFileAccess( 922 extension, extension_service_, allow_str == "true"); 923} 924 925void ExtensionSettingsHandler::HandleUninstallMessage( 926 const base::ListValue* args) { 927 CHECK_EQ(1U, args->GetSize()); 928 std::string extension_id; 929 CHECK(args->GetString(0, &extension_id)); 930 const Extension* extension = 931 extension_service_->GetInstalledExtension(extension_id); 932 if (!extension) 933 return; 934 935 if (!management_policy_->UserMayModifySettings(extension, NULL)) { 936 LOG(ERROR) << "Attempt to uninstall an extension that is non-usermanagable " 937 << "was made. Extension id : " << extension->id(); 938 return; 939 } 940 941 if (!extension_id_prompting_.empty()) 942 return; // Only one prompt at a time. 943 944 extension_id_prompting_ = extension_id; 945 946 GetExtensionUninstallDialog()->ConfirmUninstall(extension); 947} 948 949void ExtensionSettingsHandler::HandleOptionsMessage( 950 const base::ListValue* args) { 951 const Extension* extension = GetActiveExtension(args); 952 if (!extension || ManifestURL::GetOptionsPage(extension).is_empty()) 953 return; 954 ExtensionTabUtil::OpenOptionsPage(extension, 955 chrome::FindBrowserWithWebContents(web_ui()->GetWebContents())); 956} 957 958void ExtensionSettingsHandler::HandlePermissionsMessage( 959 const base::ListValue* args) { 960 std::string extension_id(UTF16ToUTF8(ExtractStringValue(args))); 961 CHECK(!extension_id.empty()); 962 const Extension* extension = 963 extension_service_->GetExtensionById(extension_id, true); 964 if (!extension) 965 extension = extension_service_->GetTerminatedExtension(extension_id); 966 if (!extension) 967 return; 968 969 if (!extension_id_prompting_.empty()) 970 return; // Only one prompt at a time. 971 972 extension_id_prompting_ = extension->id(); 973 prompt_.reset(new ExtensionInstallPrompt(web_contents())); 974 std::vector<base::FilePath> retained_file_paths; 975 if (extension->HasAPIPermission(APIPermission::kFileSystem)) { 976 std::vector<apps::SavedFileEntry> retained_file_entries = 977 apps::SavedFilesService::Get(Profile::FromWebUI( 978 web_ui()))->GetAllFileEntries(extension_id_prompting_); 979 for (size_t i = 0; i < retained_file_entries.size(); ++i) { 980 retained_file_paths.push_back(retained_file_entries[i].path); 981 } 982 } 983 // The BrokerDelegate manages its own lifetime. 984 prompt_->ReviewPermissions( 985 new BrokerDelegate(AsWeakPtr()), extension, retained_file_paths); 986} 987 988void ExtensionSettingsHandler::HandleShowButtonMessage( 989 const base::ListValue* args) { 990 const Extension* extension = GetActiveExtension(args); 991 if (!extension) 992 return; 993 ExtensionActionAPI::SetBrowserActionVisibility( 994 extension_service_->extension_prefs(), extension->id(), true); 995} 996 997void ExtensionSettingsHandler::HandleAutoUpdateMessage( 998 const base::ListValue* args) { 999 ExtensionUpdater* updater = extension_service_->updater(); 1000 if (updater) { 1001 ExtensionUpdater::CheckParams params; 1002 params.install_immediately = true; 1003 updater->CheckNow(params); 1004 } 1005} 1006 1007void ExtensionSettingsHandler::HandleLoadUnpackedExtensionMessage( 1008 const base::ListValue* args) { 1009 DCHECK(args->empty()); 1010 1011 base::string16 select_title = 1012 l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); 1013 1014 const int kFileTypeIndex = 0; // No file type information to index. 1015 const ui::SelectFileDialog::Type kSelectType = 1016 ui::SelectFileDialog::SELECT_FOLDER; 1017 load_extension_dialog_ = ui::SelectFileDialog::Create( 1018 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents())); 1019 load_extension_dialog_->SelectFile( 1020 kSelectType, 1021 select_title, 1022 last_unpacked_directory_, 1023 NULL, 1024 kFileTypeIndex, 1025 base::FilePath::StringType(), 1026 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(), 1027 NULL); 1028 1029 content::RecordComputedAction("Options_LoadUnpackedExtension"); 1030} 1031 1032void ExtensionSettingsHandler::ShowAlert(const std::string& message) { 1033 base::ListValue arguments; 1034 arguments.Append(base::Value::CreateStringValue(message)); 1035 web_ui()->CallJavascriptFunction("alert", arguments); 1036} 1037 1038const Extension* ExtensionSettingsHandler::GetActiveExtension( 1039 const base::ListValue* args) { 1040 std::string extension_id = UTF16ToUTF8(ExtractStringValue(args)); 1041 CHECK(!extension_id.empty()); 1042 return extension_service_->GetExtensionById(extension_id, false); 1043} 1044 1045void ExtensionSettingsHandler::MaybeUpdateAfterNotification() { 1046 WebContents* contents = web_ui()->GetWebContents(); 1047 if (!ignore_notifications_ && contents && contents->GetRenderViewHost()) 1048 HandleRequestExtensionsData(NULL); 1049 deleting_rvh_ = NULL; 1050} 1051 1052void ExtensionSettingsHandler::MaybeRegisterForNotifications() { 1053 if (registered_for_notifications_) 1054 return; 1055 1056 registered_for_notifications_ = true; 1057 Profile* profile = Profile::FromWebUI(web_ui()); 1058 1059 // Register for notifications that we need to reload the page. 1060 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, 1061 content::Source<Profile>(profile)); 1062 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 1063 content::Source<Profile>(profile)); 1064 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 1065 content::Source<Profile>(profile)); 1066 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, 1067 content::Source<Profile>(profile)); 1068 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_CREATED, 1069 content::NotificationService::AllBrowserContextsAndSources()); 1070 registrar_.Add(this, 1071 chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED, 1072 content::NotificationService::AllBrowserContextsAndSources()); 1073 registrar_.Add(this, 1074 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED, 1075 content::NotificationService::AllBrowserContextsAndSources()); 1076 registrar_.Add( 1077 this, 1078 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED, 1079 content::Source<ExtensionPrefs>( 1080 profile->GetExtensionService()->extension_prefs())); 1081 registrar_.Add(this, 1082 chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, 1083 content::NotificationService::AllBrowserContextsAndSources()); 1084 1085 registrar_.Add(this, 1086 content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, 1087 content::NotificationService::AllBrowserContextsAndSources()); 1088 1089 content::WebContentsObserver::Observe(web_ui()->GetWebContents()); 1090 1091 warning_service_observer_.Add( 1092 ExtensionSystem::Get(profile)->warning_service()); 1093 1094 error_console_observer_.Add(ErrorConsole::Get(profile)); 1095 1096 base::Closure callback = base::Bind( 1097 &ExtensionSettingsHandler::MaybeUpdateAfterNotification, 1098 AsWeakPtr()); 1099 1100 pref_registrar_.Init(profile->GetPrefs()); 1101 pref_registrar_.Add(prefs::kExtensionInstallDenyList, callback); 1102} 1103 1104std::vector<ExtensionPage> 1105ExtensionSettingsHandler::GetInspectablePagesForExtension( 1106 const Extension* extension, bool extension_is_enabled) { 1107 std::vector<ExtensionPage> result; 1108 1109 // Get the extension process's active views. 1110 extensions::ProcessManager* process_manager = 1111 ExtensionSystem::Get(extension_service_->profile())->process_manager(); 1112 GetInspectablePagesForExtensionProcess( 1113 extension, 1114 process_manager->GetRenderViewHostsForExtension(extension->id()), 1115 &result); 1116 1117 // Get shell window views 1118 GetShellWindowPagesForExtensionProfile(extension, 1119 extension_service_->profile(), &result); 1120 1121 // Include a link to start the lazy background page, if applicable. 1122 if (BackgroundInfo::HasLazyBackgroundPage(extension) && 1123 extension_is_enabled && 1124 !process_manager->GetBackgroundHostForExtension(extension->id())) { 1125 result.push_back(ExtensionPage( 1126 BackgroundInfo::GetBackgroundURL(extension), 1127 -1, 1128 -1, 1129 false, 1130 BackgroundInfo::HasGeneratedBackgroundPage(extension))); 1131 } 1132 1133 // Repeat for the incognito process, if applicable. Don't try to get 1134 // shell windows for incognito processes. 1135 if (extension_service_->profile()->HasOffTheRecordProfile() && 1136 IncognitoInfo::IsSplitMode(extension)) { 1137 extensions::ProcessManager* process_manager = 1138 ExtensionSystem::Get(extension_service_->profile()-> 1139 GetOffTheRecordProfile())->process_manager(); 1140 GetInspectablePagesForExtensionProcess( 1141 extension, 1142 process_manager->GetRenderViewHostsForExtension(extension->id()), 1143 &result); 1144 1145 if (BackgroundInfo::HasLazyBackgroundPage(extension) && 1146 extension_is_enabled && 1147 !process_manager->GetBackgroundHostForExtension(extension->id())) { 1148 result.push_back(ExtensionPage( 1149 BackgroundInfo::GetBackgroundURL(extension), 1150 -1, 1151 -1, 1152 true, 1153 BackgroundInfo::HasGeneratedBackgroundPage(extension))); 1154 } 1155 } 1156 1157 return result; 1158} 1159 1160void ExtensionSettingsHandler::GetInspectablePagesForExtensionProcess( 1161 const Extension* extension, 1162 const std::set<RenderViewHost*>& views, 1163 std::vector<ExtensionPage>* result) { 1164 bool has_generated_background_page = 1165 BackgroundInfo::HasGeneratedBackgroundPage(extension); 1166 for (std::set<RenderViewHost*>::const_iterator iter = views.begin(); 1167 iter != views.end(); ++iter) { 1168 RenderViewHost* host = *iter; 1169 WebContents* web_contents = WebContents::FromRenderViewHost(host); 1170 ViewType host_type = GetViewType(web_contents); 1171 if (host == deleting_rvh_ || 1172 VIEW_TYPE_EXTENSION_POPUP == host_type || 1173 VIEW_TYPE_EXTENSION_DIALOG == host_type) 1174 continue; 1175 1176 GURL url = web_contents->GetURL(); 1177 content::RenderProcessHost* process = host->GetProcess(); 1178 bool is_background_page = 1179 (url == BackgroundInfo::GetBackgroundURL(extension)); 1180 result->push_back( 1181 ExtensionPage(url, 1182 process->GetID(), 1183 host->GetRoutingID(), 1184 process->GetBrowserContext()->IsOffTheRecord(), 1185 is_background_page && has_generated_background_page)); 1186 } 1187} 1188 1189void ExtensionSettingsHandler::GetShellWindowPagesForExtensionProfile( 1190 const Extension* extension, 1191 Profile* profile, 1192 std::vector<ExtensionPage>* result) { 1193 apps::ShellWindowRegistry* registry = apps::ShellWindowRegistry::Get(profile); 1194 if (!registry) return; 1195 1196 const apps::ShellWindowRegistry::ShellWindowList windows = 1197 registry->GetShellWindowsForApp(extension->id()); 1198 1199 bool has_generated_background_page = 1200 BackgroundInfo::HasGeneratedBackgroundPage(extension); 1201 for (apps::ShellWindowRegistry::const_iterator it = windows.begin(); 1202 it != windows.end(); ++it) { 1203 WebContents* web_contents = (*it)->web_contents(); 1204 RenderViewHost* host = web_contents->GetRenderViewHost(); 1205 content::RenderProcessHost* process = host->GetProcess(); 1206 1207 bool is_background_page = 1208 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension)); 1209 result->push_back( 1210 ExtensionPage(web_contents->GetURL(), 1211 process->GetID(), 1212 host->GetRoutingID(), 1213 process->GetBrowserContext()->IsOffTheRecord(), 1214 is_background_page && has_generated_background_page)); 1215 } 1216} 1217 1218ExtensionUninstallDialog* 1219ExtensionSettingsHandler::GetExtensionUninstallDialog() { 1220#if !defined(OS_ANDROID) 1221 if (!extension_uninstall_dialog_.get()) { 1222 Browser* browser = chrome::FindBrowserWithWebContents( 1223 web_ui()->GetWebContents()); 1224 extension_uninstall_dialog_.reset( 1225 ExtensionUninstallDialog::Create(extension_service_->profile(), 1226 browser, this)); 1227 } 1228 return extension_uninstall_dialog_.get(); 1229#else 1230 return NULL; 1231#endif // !defined(OS_ANDROID) 1232} 1233 1234void ExtensionSettingsHandler::OnRequirementsChecked( 1235 std::string extension_id, 1236 std::vector<std::string> requirement_errors) { 1237 if (requirement_errors.empty()) { 1238 extension_service_->EnableExtension(extension_id); 1239 } else { 1240 ExtensionErrorReporter::GetInstance()->ReportError( 1241 UTF8ToUTF16(JoinString(requirement_errors, ' ')), 1242 true /* be noisy */); 1243 } 1244 requirements_checker_.reset(); 1245} 1246 1247} // namespace extensions 1248