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