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.
5 #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
7 #include "apps/app_load_service.h"
8 #include "apps/saved_files_service.h"
9 #include "base/auto_reset.h"
10 #include "base/base64.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/command_line.h"
14 #include "base/location.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/metrics/histogram.h"
17 #include "base/prefs/pref_service.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/values.h"
22 #include "base/version.h"
23 #include "chrome/browser/browser_process.h"
24 #include "chrome/browser/chrome_notification_types.h"
25 #include "chrome/browser/devtools/devtools_window.h"
26 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
27 #include "chrome/browser/extensions/component_loader.h"
28 #include "chrome/browser/extensions/crx_installer.h"
29 #include "chrome/browser/extensions/devtools_util.h"
30 #include "chrome/browser/extensions/error_console/error_console.h"
31 #include "chrome/browser/extensions/extension_action_manager.h"
32 #include "chrome/browser/extensions/extension_disabled_ui.h"
33 #include "chrome/browser/extensions/extension_error_reporter.h"
34 #include "chrome/browser/extensions/extension_management.h"
35 #include "chrome/browser/extensions/extension_service.h"
36 #include "chrome/browser/extensions/extension_tab_util.h"
37 #include "chrome/browser/extensions/extension_ui_util.h"
38 #include "chrome/browser/extensions/extension_util.h"
39 #include "chrome/browser/extensions/install_verifier.h"
40 #include "chrome/browser/extensions/path_util.h"
41 #include "chrome/browser/extensions/shared_module_service.h"
42 #include "chrome/browser/extensions/updater/extension_updater.h"
43 #include "chrome/browser/extensions/webstore_reinstaller.h"
44 #include "chrome/browser/platform_util.h"
45 #include "chrome/browser/prefs/incognito_mode_prefs.h"
46 #include "chrome/browser/profiles/profile.h"
47 #include "chrome/browser/tab_contents/background_contents.h"
48 #include "chrome/browser/ui/apps/app_info_dialog.h"
49 #include "chrome/browser/ui/browser.h"
50 #include "chrome/browser/ui/browser_finder.h"
51 #include "chrome/browser/ui/browser_window.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/chrome_version_info.h"
57 #include "chrome/common/extensions/features/feature_channel.h"
58 #include "chrome/common/pref_names.h"
59 #include "chrome/common/url_constants.h"
60 #include "chrome/grit/chromium_strings.h"
61 #include "chrome/grit/generated_resources.h"
62 #include "components/google/core/browser/google_util.h"
63 #include "components/pref_registry/pref_registry_syncable.h"
64 #include "content/public/browser/notification_service.h"
65 #include "content/public/browser/notification_source.h"
66 #include "content/public/browser/notification_types.h"
67 #include "content/public/browser/render_process_host.h"
68 #include "content/public/browser/render_view_host.h"
69 #include "content/public/browser/site_instance.h"
70 #include "content/public/browser/web_contents.h"
71 #include "content/public/browser/web_ui.h"
72 #include "content/public/browser/web_ui_data_source.h"
73 #include "extensions/browser/api/device_permissions_manager.h"
74 #include "extensions/browser/app_window/app_window.h"
75 #include "extensions/browser/app_window/app_window_registry.h"
76 #include "extensions/browser/blacklist_state.h"
77 #include "extensions/browser/extension_error.h"
78 #include "extensions/browser/extension_host.h"
79 #include "extensions/browser/extension_registry.h"
80 #include "extensions/browser/extension_system.h"
81 #include "extensions/browser/lazy_background_task_queue.h"
82 #include "extensions/browser/management_policy.h"
83 #include "extensions/browser/pref_names.h"
84 #include "extensions/browser/uninstall_reason.h"
85 #include "extensions/browser/view_type_utils.h"
86 #include "extensions/browser/warning_set.h"
87 #include "extensions/common/constants.h"
88 #include "extensions/common/extension.h"
89 #include "extensions/common/extension_icon_set.h"
90 #include "extensions/common/extension_set.h"
91 #include "extensions/common/extension_urls.h"
92 #include "extensions/common/feature_switch.h"
93 #include "extensions/common/manifest.h"
94 #include "extensions/common/manifest_handlers/background_info.h"
95 #include "extensions/common/manifest_handlers/incognito_info.h"
96 #include "extensions/common/manifest_handlers/options_page_info.h"
97 #include "extensions/common/manifest_url_handlers.h"
98 #include "extensions/common/permissions/permissions_data.h"
99 #include "extensions/common/switches.h"
100 #include "grit/browser_resources.h"
101 #include "grit/components_strings.h"
102 #include "grit/theme_resources.h"
103 #include "ui/base/l10n/l10n_util.h"
105 using base::DictionaryValue;
106 using base::ListValue;
107 using content::RenderViewHost;
108 using content::WebContents;
112 const char kAppsDeveloperToolsExtensionId[] =
113 "ohmmkhmmmpcnpikjeljgnaoabkaalbgc";
115 // Returns true if the extensions page should display the new-style extension
116 // info dialog. If false, display the old permissions dialog.
117 bool ShouldDisplayExtensionInfoDialog() {
118 #if defined(OS_MACOSX)
121 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
122 extensions::switches::kDisableExtensionInfoDialog);
128 namespace extensions {
130 ExtensionPage::ExtensionPage(const GURL& url,
131 int render_process_id,
134 bool generated_background_page)
136 render_process_id(render_process_id),
137 render_view_id(render_view_id),
138 incognito(incognito),
139 generated_background_page(generated_background_page) {
142 // The install prompt is not necessarily modal (e.g. Mac, Linux Unity). This
143 // means that the user can navigate while the dialog is up, causing the dialog
144 // handler to outlive the ExtensionSettingsHandler. That's a problem because the
145 // dialog framework will try to contact us back once the dialog is closed, which
146 // causes a crash. This class is designed to broker the message between the two
147 // objects, while managing its own lifetime so that it can outlive the
148 // ExtensionSettingsHandler and (when doing so) gracefully ignore the message
150 class BrokerDelegate : public ExtensionInstallPrompt::Delegate {
152 explicit BrokerDelegate(
153 const base::WeakPtr<ExtensionSettingsHandler>& delegate)
154 : delegate_(delegate) {}
156 // ExtensionInstallPrompt::Delegate implementation.
157 void InstallUIProceed() override {
159 delegate_->InstallUIProceed();
163 void InstallUIAbort(bool user_initiated) override {
165 delegate_->InstallUIAbort(user_initiated);
169 void AppInfoDialogClosed() {
171 delegate_->AppInfoDialogClosed();
176 base::WeakPtr<ExtensionSettingsHandler> delegate_;
178 DISALLOW_COPY_AND_ASSIGN(BrokerDelegate);
181 ///////////////////////////////////////////////////////////////////////////////
183 // ExtensionSettingsHandler
185 ///////////////////////////////////////////////////////////////////////////////
187 ExtensionSettingsHandler::ExtensionSettingsHandler()
188 : extension_service_(NULL),
189 management_policy_(NULL),
190 ignore_notifications_(false),
192 deleting_rwh_id_(-1),
193 deleting_rph_id_(-1),
194 registered_for_notifications_(false),
195 warning_service_observer_(this),
196 error_console_observer_(this),
197 extension_prefs_observer_(this),
198 extension_registry_observer_(this),
199 extension_management_observer_(this),
200 should_do_verification_check_(false) {
203 ExtensionSettingsHandler::~ExtensionSettingsHandler() {
206 ExtensionSettingsHandler::ExtensionSettingsHandler(ExtensionService* service,
207 ManagementPolicy* policy)
208 : extension_service_(service),
209 management_policy_(policy),
210 ignore_notifications_(false),
212 deleting_rwh_id_(-1),
213 deleting_rph_id_(-1),
214 registered_for_notifications_(false),
215 warning_service_observer_(this),
216 error_console_observer_(this),
217 extension_prefs_observer_(this),
218 extension_registry_observer_(this),
219 extension_management_observer_(this),
220 should_do_verification_check_(false) {
224 void ExtensionSettingsHandler::RegisterProfilePrefs(
225 user_prefs::PrefRegistrySyncable* registry) {
226 registry->RegisterBooleanPref(
227 prefs::kExtensionsUIDeveloperMode,
229 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
230 registry->RegisterBooleanPref(
231 prefs::kExtensionsUIDismissedADTPromo,
233 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
236 base::DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue(
237 const Extension* extension,
238 const std::vector<ExtensionPage>& pages,
239 const WarningService* warning_service) {
240 // The items which are to be written into app_dict are also described in
241 // chrome/browser/resources/extensions/extension_list.js in @typedef for
242 // ExtensionData. Please update it whenever you add or remove any keys here.
243 base::DictionaryValue* extension_data = new base::DictionaryValue();
244 bool enabled = extension_service_->IsExtensionEnabled(extension->id());
245 GetExtensionBasicInfo(extension, enabled, extension_data);
247 ExtensionPrefs* prefs = ExtensionPrefs::Get(extension_service_->profile());
248 int disable_reasons = prefs->GetDisableReasons(extension->id());
250 bool suspicious_install =
251 (disable_reasons & Extension::DISABLE_NOT_VERIFIED) != 0;
252 extension_data->SetBoolean("suspiciousInstall", suspicious_install);
253 if (suspicious_install)
254 should_do_verification_check_ = true;
256 bool corrupt_install =
257 (disable_reasons & Extension::DISABLE_CORRUPTED) != 0;
258 extension_data->SetBoolean("corruptInstall", corrupt_install);
260 bool managed_install =
261 !management_policy_->UserMayModifySettings(extension, NULL);
262 extension_data->SetBoolean("managedInstall", managed_install);
264 bool recommended_install =
266 management_policy_->MustRemainInstalled(extension, NULL);
267 extension_data->SetBoolean("recommendedInstall", recommended_install);
269 // Suspicious install should always be mutually exclusive to managed and/or
270 // recommended install.
271 DCHECK(!(managed_install || recommended_install) || !suspicious_install);
274 ExtensionIconSource::GetIconURL(extension,
275 extension_misc::EXTENSION_ICON_MEDIUM,
276 ExtensionIconSet::MATCH_BIGGER,
278 if (Manifest::IsUnpackedLocation(extension->location())) {
279 extension_data->SetString("path", extension->path().value());
280 extension_data->SetString(
282 extensions::path_util::PrettifyPath(extension->path()).value());
284 extension_data->SetString("icon", icon.spec());
285 extension_data->SetBoolean("isUnpacked",
286 Manifest::IsUnpackedLocation(extension->location()));
287 extension_data->SetBoolean("isFromStore",
288 extension->location() == Manifest::INTERNAL &&
289 ManifestURL::UpdatesFromGallery(extension));
290 ExtensionRegistry* registry =
291 ExtensionRegistry::Get(extension_service_->profile());
292 extension_data->SetBoolean(
294 registry->terminated_extensions().Contains(extension->id()));
295 extension_data->SetBoolean("enabledIncognito",
296 util::IsIncognitoEnabled(extension->id(), extension_service_->profile()));
297 extension_data->SetBoolean("incognitoCanBeEnabled",
298 extension->can_be_incognito_enabled());
299 extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access());
300 extension_data->SetBoolean("allowFileAccess",
301 util::AllowFileAccess(extension->id(), extension_service_->profile()));
302 extension_data->SetBoolean("allow_reload",
303 Manifest::IsUnpackedLocation(extension->location()));
304 extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app());
305 extension_data->SetBoolean("is_platform_app", extension->is_platform_app());
306 extension_data->SetBoolean("homepageProvided",
307 ManifestURL::SpecifiedHomepageURL(extension));
308 extension_data->SetBoolean("optionsOpenInTab",
309 OptionsPageInfo::ShouldOpenInTab(extension));
310 extension_data->SetString("optionsPageHref",
311 OptionsPageInfo::GetOptionsPage(extension).spec());
312 extension_data->SetBoolean("enableExtensionInfoDialog",
313 ShouldDisplayExtensionInfoDialog());
315 // Add dependent extensions.
316 base::ListValue* dependents_list = new base::ListValue;
317 if (extension->is_shared_module()) {
318 scoped_ptr<ExtensionSet> dependent_extensions =
319 extension_service_->shared_module_service()->GetDependentExtensions(
321 for (ExtensionSet::const_iterator i = dependent_extensions->begin();
322 i != dependent_extensions->end();
324 base::DictionaryValue* dependent_entry = new base::DictionaryValue;
325 dependent_entry->SetString("id", (*i)->id());
326 dependent_entry->SetString("name", (*i)->name());
327 dependents_list->Append(dependent_entry);
330 extension_data->Set("dependentExtensions", dependents_list);
332 // Extensions only want all URL access if:
333 // - The feature is enabled for the given extension.
334 // - The extension has access to enough urls that we can't just let it run
335 // on those specified in the permissions.
336 bool wants_all_urls =
337 util::ScriptsMayRequireActionForExtension(extension) &&
338 (extension->permissions_data()->HasWithheldImpliedAllHosts() ||
339 util::AllowedScriptingOnAllUrls(
340 extension->id(), extension_service_->GetBrowserContext()));
341 extension_data->SetBoolean("wantsAllUrls", wants_all_urls);
342 extension_data->SetBoolean(
344 util::AllowedScriptingOnAllUrls(
346 extension_service_->GetBrowserContext()));
348 base::string16 location_text;
349 if (Manifest::IsPolicyLocation(extension->location()) ||
350 (extension->location() == Manifest::EXTERNAL_PREF_DOWNLOAD &&
351 recommended_install)) {
352 location_text = l10n_util::GetStringUTF16(
353 IDS_OPTIONS_INSTALL_LOCATION_ENTERPRISE);
354 } else if (extension->location() == Manifest::INTERNAL &&
355 !ManifestURL::UpdatesFromGallery(extension)) {
356 location_text = l10n_util::GetStringUTF16(
357 IDS_OPTIONS_INSTALL_LOCATION_UNKNOWN);
358 } else if (extension->location() == Manifest::EXTERNAL_REGISTRY) {
359 location_text = l10n_util::GetStringUTF16(
360 IDS_OPTIONS_INSTALL_LOCATION_3RD_PARTY);
361 } else if (extension->is_shared_module()) {
362 location_text = l10n_util::GetStringUTF16(
363 IDS_OPTIONS_INSTALL_LOCATION_SHARED_MODULE);
365 extension_data->SetString("locationText", location_text);
367 base::string16 blacklist_text;
368 switch (prefs->GetExtensionBlacklistState(extension->id())) {
369 case BLACKLISTED_SECURITY_VULNERABILITY:
370 blacklist_text = l10n_util::GetStringUTF16(
371 IDS_OPTIONS_BLACKLISTED_SECURITY_VULNERABILITY);
374 case BLACKLISTED_CWS_POLICY_VIOLATION:
375 blacklist_text = l10n_util::GetStringUTF16(
376 IDS_OPTIONS_BLACKLISTED_CWS_POLICY_VIOLATION);
379 case BLACKLISTED_POTENTIALLY_UNWANTED:
380 blacklist_text = l10n_util::GetStringUTF16(
381 IDS_OPTIONS_BLACKLISTED_POTENTIALLY_UNWANTED);
387 extension_data->SetString("blacklistText", blacklist_text);
389 // Force unpacked extensions to show at the top.
390 if (Manifest::IsUnpackedLocation(extension->location()))
391 extension_data->SetInteger("order", 1);
393 extension_data->SetInteger("order", 2);
395 if (!ExtensionActionAPI::GetBrowserActionVisibility(prefs, extension->id())) {
396 extension_data->SetBoolean("enable_show_button", true);
400 base::ListValue* views = new base::ListValue;
401 for (std::vector<ExtensionPage>::const_iterator iter = pages.begin();
402 iter != pages.end(); ++iter) {
403 base::DictionaryValue* view_value = new base::DictionaryValue;
404 if (iter->url.scheme() == kExtensionScheme) {
406 view_value->SetString("path", iter->url.path().substr(1));
408 // For live pages, use the full URL.
409 view_value->SetString("path", iter->url.spec());
411 view_value->SetInteger("renderViewId", iter->render_view_id);
412 view_value->SetInteger("renderProcessId", iter->render_process_id);
413 view_value->SetBoolean("incognito", iter->incognito);
414 view_value->SetBoolean("generatedBackgroundPage",
415 iter->generated_background_page);
416 views->Append(view_value);
418 extension_data->Set("views", views);
419 ExtensionActionManager* extension_action_manager =
420 ExtensionActionManager::Get(extension_service_->profile());
421 extension_data->SetBoolean(
423 extension_action_manager->GetBrowserAction(*extension) ||
424 extension_action_manager->GetPageAction(*extension));
427 if (warning_service) {
428 std::vector<std::string> warnings =
429 warning_service->GetWarningMessagesForExtension(extension->id());
431 if (!warnings.empty()) {
432 base::ListValue* warnings_list = new base::ListValue;
433 for (std::vector<std::string>::const_iterator iter = warnings.begin();
434 iter != warnings.end(); ++iter) {
435 warnings_list->Append(new base::StringValue(*iter));
437 extension_data->Set("warnings", warnings_list);
441 // If the ErrorConsole is enabled and the extension is unpacked, use the more
442 // detailed errors from the ErrorConsole. Otherwise, use the install warnings
443 // (using both is redundant).
444 ErrorConsole* error_console =
445 ErrorConsole::Get(extension_service_->profile());
446 bool error_console_is_enabled =
447 error_console->IsEnabledForChromeExtensionsPage();
448 extension_data->SetBoolean("wantsErrorCollection", error_console_is_enabled);
449 if (error_console_is_enabled) {
450 extension_data->SetBoolean("errorCollectionEnabled",
451 error_console->IsReportingEnabledForExtension(
453 const ErrorList& errors =
454 error_console->GetErrorsForExtension(extension->id());
455 if (!errors.empty()) {
456 scoped_ptr<base::ListValue> manifest_errors(new base::ListValue);
457 scoped_ptr<base::ListValue> runtime_errors(new base::ListValue);
458 for (ErrorList::const_iterator iter = errors.begin();
459 iter != errors.end(); ++iter) {
460 if ((*iter)->type() == ExtensionError::MANIFEST_ERROR) {
461 manifest_errors->Append((*iter)->ToValue().release());
462 } else { // Handle runtime error.
463 const RuntimeError* error = static_cast<const RuntimeError*>(*iter);
464 scoped_ptr<base::DictionaryValue> value = error->ToValue();
466 !(deleting_rwh_id_ == error->render_view_id() &&
467 deleting_rph_id_ == error->render_process_id()) &&
468 RenderViewHost::FromID(error->render_process_id(),
469 error->render_view_id()) != NULL;
470 value->SetBoolean("canInspect", can_inspect);
471 runtime_errors->Append(value.release());
474 if (!manifest_errors->empty())
475 extension_data->Set("manifestErrors", manifest_errors.release());
476 if (!runtime_errors->empty())
477 extension_data->Set("runtimeErrors", runtime_errors.release());
479 } else if (Manifest::IsUnpackedLocation(extension->location())) {
480 const std::vector<InstallWarning>& install_warnings =
481 extension->install_warnings();
482 if (!install_warnings.empty()) {
483 scoped_ptr<base::ListValue> list(new base::ListValue());
484 for (std::vector<InstallWarning>::const_iterator it =
485 install_warnings.begin(); it != install_warnings.end(); ++it) {
486 base::DictionaryValue* item = new base::DictionaryValue();
487 item->SetString("message", it->message);
490 extension_data->Set("installWarnings", list.release());
494 return extension_data;
497 void ExtensionSettingsHandler::GetLocalizedValues(
498 content::WebUIDataSource* source) {
499 source->AddString("extensionSettings",
500 l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE));
502 source->AddString("extensionSettingsDeveloperMode",
503 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK));
504 source->AddString("extensionSettingsNoExtensions",
505 l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED));
507 "extensionSettingsSuggestGallery",
508 l10n_util::GetStringFUTF16(
509 IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY,
511 google_util::AppendGoogleLocaleParam(
512 GURL(extension_urls::GetWebstoreExtensionsCategoryURL()),
513 g_browser_process->GetApplicationLocale()).spec())));
514 source->AddString("extensionSettingsGetMoreExtensions",
515 l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS));
517 "extensionSettingsGetMoreExtensionsUrl",
519 google_util::AppendGoogleLocaleParam(
520 GURL(extension_urls::GetWebstoreExtensionsCategoryURL()),
521 g_browser_process->GetApplicationLocale()).spec()));
522 source->AddString("extensionSettingsExtensionId",
523 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID));
524 source->AddString("extensionSettingsExtensionPath",
525 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PATH));
526 source->AddString("extensionSettingsInspectViews",
527 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS));
528 source->AddString("extensionSettingsInstallWarnings",
529 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALL_WARNINGS));
530 source->AddString("viewIncognito",
531 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO));
532 source->AddString("viewInactive",
533 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INACTIVE));
534 source->AddString("backgroundPage",
535 l10n_util::GetStringUTF16(IDS_EXTENSIONS_BACKGROUND_PAGE));
536 source->AddString("extensionSettingsEnable",
537 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE));
538 source->AddString("extensionSettingsEnabled",
539 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLED));
540 source->AddString("extensionSettingsRemove",
541 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REMOVE));
542 source->AddString("extensionSettingsEnableIncognito",
543 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO));
544 source->AddString("extensionSettingsEnableErrorCollection",
545 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_ERROR_COLLECTION));
546 source->AddString("extensionSettingsAllowFileAccess",
547 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS));
548 source->AddString("extensionSettingsAllowOnAllUrls",
549 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_ON_ALL_URLS));
550 source->AddString("extensionSettingsIncognitoWarning",
551 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING));
552 source->AddString("extensionSettingsReloadTerminated",
553 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_TERMINATED));
554 source->AddString("extensionSettingsRepairCorrupted",
555 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REPAIR_CORRUPTED));
556 source->AddString("extensionSettingsLaunch",
557 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LAUNCH));
558 source->AddString("extensionSettingsReloadUnpacked",
559 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_UNPACKED));
560 source->AddString("extensionSettingsOptions",
561 l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS_LINK));
562 if (ShouldDisplayExtensionInfoDialog()) {
563 source->AddString("extensionSettingsPermissions",
564 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INFO_LINK));
567 "extensionSettingsPermissions",
568 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PERMISSIONS_LINK));
570 source->AddString("extensionSettingsVisitWebsite",
571 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSITE));
572 source->AddString("extensionSettingsVisitWebStore",
573 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSTORE));
574 source->AddString("extensionSettingsPolicyControlled",
575 l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED));
576 source->AddString("extensionSettingsPolicyRecommeneded",
577 l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_RECOMMENDED));
578 source->AddString("extensionSettingsDependentExtensions",
579 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEPENDENT_EXTENSIONS));
580 source->AddString("extensionSettingsSupervisedUser",
581 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_SUPERVISED_USER));
582 source->AddString("extensionSettingsCorruptInstall",
583 l10n_util::GetStringUTF16(
584 IDS_EXTENSIONS_CORRUPTED_EXTENSION));
585 source->AddString("extensionSettingsSuspiciousInstall",
586 l10n_util::GetStringFUTF16(
587 IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE,
588 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)));
589 source->AddString("extensionSettingsLearnMore",
590 l10n_util::GetStringUTF16(IDS_LEARN_MORE));
591 source->AddString("extensionSettingsSuspiciousInstallHelpUrl",
593 google_util::AppendGoogleLocaleParam(
594 GURL(chrome::kRemoveNonCWSExtensionURL),
595 g_browser_process->GetApplicationLocale()).spec()));
596 source->AddString("extensionSettingsShowButton",
597 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON));
598 source->AddString("extensionSettingsLoadUnpackedButton",
599 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON));
600 source->AddString("extensionSettingsPackButton",
601 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON));
602 source->AddString("extensionSettingsCommandsLink",
603 l10n_util::GetStringUTF16(IDS_EXTENSIONS_COMMANDS_CONFIGURE));
604 source->AddString("extensionSettingsUpdateButton",
605 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON));
607 "extensionSettingsAppsDevToolsPromoHTML",
608 l10n_util::GetStringFUTF16(
609 IDS_EXTENSIONS_APPS_DEV_TOOLS_PROMO_HTML,
611 google_util::AppendGoogleLocaleParam(
612 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() +
613 kAppsDeveloperToolsExtensionId),
614 g_browser_process->GetApplicationLocale()).spec())));
616 "extensionSettingsAppDevToolsPromoClose",
617 l10n_util::GetStringUTF16(IDS_CLOSE));
618 source->AddString("extensionSettingsCrashMessage",
619 l10n_util::GetStringUTF16(IDS_EXTENSIONS_CRASHED_EXTENSION));
620 source->AddString("extensionSettingsInDevelopment",
621 l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT));
622 source->AddString("extensionSettingsWarningsTitle",
623 l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_TITLE));
624 source->AddString("extensionSettingsShowDetails",
625 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS));
626 source->AddString("extensionSettingsHideDetails",
627 l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS));
629 // TODO(estade): comb through the above strings to find ones no longer used in
631 source->AddString("extensionUninstall",
632 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
635 void ExtensionSettingsHandler::RenderViewDeleted(
636 RenderViewHost* render_view_host) {
637 deleting_rvh_ = render_view_host;
638 Profile* source_profile = Profile::FromBrowserContext(
639 render_view_host->GetSiteInstance()->GetBrowserContext());
640 if (!Profile::FromWebUI(web_ui())->IsSameProfile(source_profile))
642 MaybeUpdateAfterNotification();
645 void ExtensionSettingsHandler::DidStartNavigationToPendingEntry(
647 content::NavigationController::ReloadType reload_type) {
648 if (reload_type != content::NavigationController::NO_RELOAD)
649 ReloadUnpackedExtensions();
652 void ExtensionSettingsHandler::RegisterMessages() {
653 // Don't override an |extension_service_| or |management_policy_| injected
655 if (!extension_service_) {
656 Profile* profile = Profile::FromWebUI(web_ui())->GetOriginalProfile();
658 extensions::ExtensionSystem::Get(profile)->extension_service();
660 if (!management_policy_) {
661 management_policy_ = ExtensionSystem::Get(
662 extension_service_->profile())->management_policy();
665 web_ui()->RegisterMessageCallback("extensionSettingsRequestExtensionsData",
666 base::Bind(&ExtensionSettingsHandler::HandleRequestExtensionsData,
668 web_ui()->RegisterMessageCallback("extensionSettingsToggleDeveloperMode",
669 base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode,
671 web_ui()->RegisterMessageCallback("extensionSettingsInspect",
672 base::Bind(&ExtensionSettingsHandler::HandleInspectMessage,
674 web_ui()->RegisterMessageCallback("extensionSettingsLaunch",
675 base::Bind(&ExtensionSettingsHandler::HandleLaunchMessage,
677 web_ui()->RegisterMessageCallback("extensionSettingsReload",
678 base::Bind(&ExtensionSettingsHandler::HandleReloadMessage,
680 web_ui()->RegisterMessageCallback("extensionSettingsRepair",
681 base::Bind(&ExtensionSettingsHandler::HandleRepairMessage,
683 web_ui()->RegisterMessageCallback("extensionSettingsEnable",
684 base::Bind(&ExtensionSettingsHandler::HandleEnableMessage,
686 web_ui()->RegisterMessageCallback("extensionSettingsEnableIncognito",
687 base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage,
689 web_ui()->RegisterMessageCallback("extensionSettingsEnableErrorCollection",
690 base::Bind(&ExtensionSettingsHandler::HandleEnableErrorCollectionMessage,
692 web_ui()->RegisterMessageCallback("extensionSettingsAllowFileAccess",
693 base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage,
695 web_ui()->RegisterMessageCallback("extensionSettingsAllowOnAllUrls",
696 base::Bind(&ExtensionSettingsHandler::HandleAllowOnAllUrlsMessage,
698 web_ui()->RegisterMessageCallback("extensionSettingsUninstall",
699 base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage,
701 web_ui()->RegisterMessageCallback("extensionSettingsOptions",
702 base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage,
704 web_ui()->RegisterMessageCallback("extensionSettingsPermissions",
705 base::Bind(&ExtensionSettingsHandler::HandlePermissionsMessage,
707 web_ui()->RegisterMessageCallback("extensionSettingsShowButton",
708 base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage,
710 web_ui()->RegisterMessageCallback("extensionSettingsAutoupdate",
711 base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage,
713 web_ui()->RegisterMessageCallback("extensionSettingsDismissADTPromo",
714 base::Bind(&ExtensionSettingsHandler::HandleDismissADTPromoMessage,
716 web_ui()->RegisterMessageCallback("extensionSettingsShowPath",
717 base::Bind(&ExtensionSettingsHandler::HandleShowPath,
721 void ExtensionSettingsHandler::OnErrorAdded(const ExtensionError* error) {
722 MaybeUpdateAfterNotification();
725 void ExtensionSettingsHandler::Observe(
727 const content::NotificationSource& source,
728 const content::NotificationDetails& details) {
729 Profile* profile = Profile::FromWebUI(web_ui());
730 Profile* source_profile = NULL;
732 // We listen for notifications that will result in the page being
733 // repopulated with data twice for the same event in certain cases.
734 // For instance, EXTENSION_LOADED & EXTENSION_HOST_CREATED because
735 // we don't know about the views for an extension at EXTENSION_LOADED, but
736 // if we only listen to EXTENSION_HOST_CREATED, we'll miss extensions
737 // that don't have a process at startup.
739 // Doing it this way gets everything but causes the page to be rendered
740 // more than we need. It doesn't seem to result in any noticeable flicker.
741 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED:
742 deleting_rvh_ = content::Details<BackgroundContents>(details)->
743 web_contents()->GetRenderViewHost();
745 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED:
746 case extensions::NOTIFICATION_EXTENSION_HOST_CREATED:
747 source_profile = content::Source<Profile>(source).ptr();
748 if (!profile->IsSameProfile(source_profile))
750 MaybeUpdateAfterNotification();
752 case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
753 content::RenderWidgetHost* rwh =
754 content::Source<content::RenderWidgetHost>(source).ptr();
755 deleting_rwh_id_ = rwh->GetRoutingID();
756 deleting_rph_id_ = rwh->GetProcess()->GetID();
757 MaybeUpdateAfterNotification();
760 case extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED:
761 case extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED:
762 MaybeUpdateAfterNotification();
764 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED:
765 // This notification is sent when the extension host destruction begins,
766 // not when it finishes. We use PostTask to delay the update until after
767 // the destruction finishes.
768 base::MessageLoop::current()->PostTask(
770 base::Bind(&ExtensionSettingsHandler::MaybeUpdateAfterNotification,
778 void ExtensionSettingsHandler::OnExtensionLoaded(
779 content::BrowserContext* browser_context,
780 const Extension* extension) {
781 MaybeUpdateAfterNotification();
784 void ExtensionSettingsHandler::OnExtensionUnloaded(
785 content::BrowserContext* browser_context,
786 const Extension* extension,
787 UnloadedExtensionInfo::Reason reason) {
788 MaybeUpdateAfterNotification();
791 void ExtensionSettingsHandler::OnExtensionUninstalled(
792 content::BrowserContext* browser_context,
793 const Extension* extension,
794 extensions::UninstallReason reason) {
795 MaybeUpdateAfterNotification();
798 void ExtensionSettingsHandler::OnExtensionDisableReasonsChanged(
799 const std::string& extension_id, int disable_reasons) {
800 MaybeUpdateAfterNotification();
803 void ExtensionSettingsHandler::OnExtensionManagementSettingsChanged() {
804 MaybeUpdateAfterNotification();
807 void ExtensionSettingsHandler::ExtensionUninstallAccepted() {
808 DCHECK(!extension_id_prompting_.empty());
810 bool was_terminated = false;
812 // The extension can be uninstalled in another window while the UI was
813 // showing. Do nothing in that case.
814 const Extension* extension =
815 extension_service_->GetExtensionById(extension_id_prompting_, true);
818 ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))->GetExtensionById(
819 extension_id_prompting_, ExtensionRegistry::TERMINATED);
820 was_terminated = true;
825 extension_service_->UninstallExtension(
826 extension_id_prompting_,
827 extensions::UNINSTALL_REASON_USER_INITIATED,
828 base::Bind(&base::DoNothing),
830 extension_id_prompting_ = "";
832 // There will be no EXTENSION_UNLOADED notification for terminated
833 // extensions as they were already unloaded.
835 HandleRequestExtensionsData(NULL);
838 void ExtensionSettingsHandler::ExtensionUninstallCanceled() {
839 extension_id_prompting_ = "";
842 void ExtensionSettingsHandler::ExtensionWarningsChanged() {
843 MaybeUpdateAfterNotification();
846 // This is called when the user clicks "Revoke File/Device Access."
847 void ExtensionSettingsHandler::InstallUIProceed() {
848 Profile* profile = Profile::FromWebUI(web_ui());
849 extensions::DevicePermissionsManager::Get(profile)
850 ->Clear(extension_id_prompting_);
851 apps::SavedFilesService::Get(profile)->ClearQueue(
852 extension_service_->GetExtensionById(extension_id_prompting_, true));
853 apps::AppLoadService::Get(profile)
854 ->RestartApplicationIfRunning(extension_id_prompting_);
855 extension_id_prompting_.clear();
858 void ExtensionSettingsHandler::InstallUIAbort(bool user_initiated) {
859 extension_id_prompting_.clear();
862 void ExtensionSettingsHandler::AppInfoDialogClosed() {
863 extension_id_prompting_.clear();
866 void ExtensionSettingsHandler::ReloadUnpackedExtensions() {
867 const ExtensionSet* extensions = extension_service_->extensions();
868 std::vector<const Extension*> unpacked_extensions;
869 for (ExtensionSet::const_iterator extension = extensions->begin();
870 extension != extensions->end(); ++extension) {
871 if (Manifest::IsUnpackedLocation((*extension)->location()))
872 unpacked_extensions.push_back(extension->get());
875 for (std::vector<const Extension*>::iterator iter =
876 unpacked_extensions.begin(); iter != unpacked_extensions.end(); ++iter) {
877 extension_service_->ReloadExtensionWithQuietFailure((*iter)->id());
881 void ExtensionSettingsHandler::HandleRequestExtensionsData(
882 const base::ListValue* args) {
883 // The items which are to be written into results are also described in
884 // chrome/browser/resources/extensions/extensions.js in @typedef for
885 // ExtensionDataResponse. Please update it whenever you add or remove any keys
887 base::DictionaryValue results;
889 Profile* profile = Profile::FromWebUI(web_ui());
891 // Add the extensions to the results structure.
892 base::ListValue* extensions_list = new base::ListValue();
894 WarningService* warnings = WarningService::Get(profile);
896 ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
897 const ExtensionSet& enabled_set = registry->enabled_extensions();
898 for (ExtensionSet::const_iterator extension = enabled_set.begin();
899 extension != enabled_set.end(); ++extension) {
900 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) {
901 extensions_list->Append(CreateExtensionDetailValue(
903 GetInspectablePagesForExtension(extension->get(), true),
907 const ExtensionSet& disabled_set = registry->disabled_extensions();
908 for (ExtensionSet::const_iterator extension = disabled_set.begin();
909 extension != disabled_set.end(); ++extension) {
910 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) {
911 extensions_list->Append(CreateExtensionDetailValue(
913 GetInspectablePagesForExtension(extension->get(), false),
917 const ExtensionSet& terminated_set = registry->terminated_extensions();
918 std::vector<ExtensionPage> empty_pages;
919 for (ExtensionSet::const_iterator extension = terminated_set.begin();
920 extension != terminated_set.end(); ++extension) {
921 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) {
922 extensions_list->Append(CreateExtensionDetailValue(
924 empty_pages, // Terminated process has no active pages.
928 results.Set("extensions", extensions_list);
930 bool is_supervised = profile->IsSupervised();
931 bool incognito_available =
932 IncognitoModePrefs::GetAvailability(profile->GetPrefs()) !=
933 IncognitoModePrefs::DISABLED;
934 bool developer_mode =
936 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
937 results.SetBoolean("profileIsSupervised", is_supervised);
938 results.SetBoolean("incognitoAvailable", incognito_available);
939 results.SetBoolean("developerMode", developer_mode);
941 // Promote the Chrome Apps & Extensions Developer Tools if they are not
942 // installed and the user has not previously dismissed the warning.
943 bool promote_apps_dev_tools = false;
944 if (!ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))->
945 GetExtensionById(kAppsDeveloperToolsExtensionId,
946 ExtensionRegistry::EVERYTHING) &&
947 !profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDismissedADTPromo)) {
948 promote_apps_dev_tools = true;
950 results.SetBoolean("promoteAppsDevTools", promote_apps_dev_tools);
952 const bool load_unpacked_disabled =
953 ExtensionManagementFactory::GetForBrowserContext(profile)
954 ->BlacklistedByDefault();
955 results.SetBoolean("loadUnpackedDisabled", load_unpacked_disabled);
957 web_ui()->CallJavascriptFunction(
958 "extensions.ExtensionSettings.returnExtensionsData", results);
960 MaybeRegisterForNotifications();
961 UMA_HISTOGRAM_BOOLEAN("ExtensionSettings.ShouldDoVerificationCheck",
962 should_do_verification_check_);
963 if (should_do_verification_check_) {
964 should_do_verification_check_ = false;
965 ExtensionSystem::Get(Profile::FromWebUI(web_ui()))
967 ->VerifyAllExtensions();
971 void ExtensionSettingsHandler::HandleToggleDeveloperMode(
972 const base::ListValue* args) {
973 Profile* profile = Profile::FromWebUI(web_ui());
974 if (profile->IsSupervised())
977 bool developer_mode =
978 !profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
979 profile->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode,
983 void ExtensionSettingsHandler::HandleInspectMessage(
984 const base::ListValue* args) {
985 std::string extension_id;
986 std::string render_process_id_str;
987 std::string render_view_id_str;
988 int render_process_id;
991 CHECK_EQ(4U, args->GetSize());
992 CHECK(args->GetString(0, &extension_id));
993 CHECK(args->GetString(1, &render_process_id_str));
994 CHECK(args->GetString(2, &render_view_id_str));
995 CHECK(args->GetBoolean(3, &incognito));
996 CHECK(base::StringToInt(render_process_id_str, &render_process_id));
997 CHECK(base::StringToInt(render_view_id_str, &render_view_id));
999 if (render_process_id == -1) {
1000 // This message is for a lazy background page. Start the page if necessary.
1001 const Extension* extension =
1002 extension_service_->extensions()->GetByID(extension_id);
1004 Profile* profile = Profile::FromWebUI(web_ui());
1006 profile = profile->GetOffTheRecordProfile();
1007 devtools_util::InspectBackgroundPage(extension, profile);
1011 RenderViewHost* host = RenderViewHost::FromID(render_process_id,
1013 if (!host || !WebContents::FromRenderViewHost(host)) {
1014 // This can happen if the host has gone away since the page was displayed.
1018 DevToolsWindow::OpenDevToolsWindow(WebContents::FromRenderViewHost(host));
1021 void ExtensionSettingsHandler::HandleLaunchMessage(
1022 const base::ListValue* args) {
1023 CHECK_EQ(1U, args->GetSize());
1024 std::string extension_id;
1025 CHECK(args->GetString(0, &extension_id));
1026 const Extension* extension =
1027 extension_service_->GetExtensionById(extension_id, false);
1028 OpenApplication(AppLaunchParams(extension_service_->profile(), extension,
1029 extensions::LAUNCH_CONTAINER_WINDOW,
1033 void ExtensionSettingsHandler::HandleReloadMessage(
1034 const base::ListValue* args) {
1035 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1036 CHECK(!extension_id.empty());
1037 extension_service_->ReloadExtensionWithQuietFailure(extension_id);
1040 void ExtensionSettingsHandler::HandleRepairMessage(
1041 const base::ListValue* args) {
1042 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1043 CHECK(!extension_id.empty());
1044 scoped_refptr<WebstoreReinstaller> reinstaller(new WebstoreReinstaller(
1047 base::Bind(&ExtensionSettingsHandler::OnReinstallComplete,
1049 reinstaller->BeginReinstall();
1052 void ExtensionSettingsHandler::HandleEnableMessage(
1053 const base::ListValue* args) {
1054 CHECK_EQ(2U, args->GetSize());
1055 std::string extension_id, enable_str;
1056 CHECK(args->GetString(0, &extension_id));
1057 CHECK(args->GetString(1, &enable_str));
1059 const Extension* extension =
1060 extension_service_->GetInstalledExtension(extension_id);
1064 if (!management_policy_->UserMayModifySettings(extension, NULL)) {
1065 LOG(ERROR) << "An attempt was made to enable an extension that is "
1066 << "non-usermanagable. Extension id: " << extension->id();
1070 if (enable_str == "true") {
1071 ExtensionPrefs* prefs = ExtensionPrefs::Get(extension_service_->profile());
1072 if (prefs->DidExtensionEscalatePermissions(extension_id)) {
1073 ShowExtensionDisabledDialog(
1074 extension_service_, web_ui()->GetWebContents(), extension);
1075 } else if ((prefs->GetDisableReasons(extension_id) &
1076 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) &&
1077 !requirements_checker_.get()) {
1078 // Recheck the requirements.
1079 scoped_refptr<const Extension> extension =
1080 extension_service_->GetExtensionById(extension_id,
1081 true /* include disabled */);
1082 requirements_checker_.reset(new RequirementsChecker);
1083 requirements_checker_->Check(
1085 base::Bind(&ExtensionSettingsHandler::OnRequirementsChecked,
1086 AsWeakPtr(), extension_id));
1088 extension_service_->EnableExtension(extension_id);
1091 extension_service_->DisableExtension(
1092 extension_id, Extension::DISABLE_USER_ACTION);
1096 void ExtensionSettingsHandler::HandleEnableIncognitoMessage(
1097 const base::ListValue* args) {
1098 CHECK_EQ(2U, args->GetSize());
1099 std::string extension_id, enable_str;
1100 CHECK(args->GetString(0, &extension_id));
1101 CHECK(args->GetString(1, &enable_str));
1102 const Extension* extension =
1103 extension_service_->GetInstalledExtension(extension_id);
1107 // Flipping the incognito bit will generate unload/load notifications for the
1108 // extension, but we don't want to reload the page, because a) we've already
1109 // updated the UI to reflect the change, and b) we want the yellow warning
1110 // text to stay until the user has left the page.
1112 // TODO(aa): This creates crappiness in some cases. For example, in a main
1113 // window, when toggling this, the browser action will flicker because it gets
1114 // unloaded, then reloaded. It would be better to have a dedicated
1115 // notification for this case.
1117 // Bug: http://crbug.com/41384
1118 base::AutoReset<bool> auto_reset_ignore_notifications(
1119 &ignore_notifications_, true);
1120 util::SetIsIncognitoEnabled(extension->id(),
1121 extension_service_->profile(),
1122 enable_str == "true");
1125 void ExtensionSettingsHandler::HandleEnableErrorCollectionMessage(
1126 const base::ListValue* args) {
1127 CHECK_EQ(2u, args->GetSize());
1128 std::string extension_id;
1129 std::string enable_str;
1130 CHECK(args->GetString(0, &extension_id));
1131 CHECK(args->GetString(1, &enable_str));
1132 bool enabled = enable_str == "true";
1133 ErrorConsole::Get(Profile::FromWebUI(web_ui()))
1134 ->SetReportingAllForExtension(extension_id, enabled);
1137 void ExtensionSettingsHandler::HandleAllowFileAccessMessage(
1138 const base::ListValue* args) {
1139 CHECK_EQ(2U, args->GetSize());
1140 std::string extension_id, allow_str;
1141 CHECK(args->GetString(0, &extension_id));
1142 CHECK(args->GetString(1, &allow_str));
1143 const Extension* extension =
1144 extension_service_->GetInstalledExtension(extension_id);
1148 if (!management_policy_->UserMayModifySettings(extension, NULL)) {
1149 LOG(ERROR) << "An attempt was made to change allow file access of an"
1150 << " extension that is non-usermanagable. Extension id : "
1155 util::SetAllowFileAccess(
1156 extension_id, extension_service_->profile(), allow_str == "true");
1159 void ExtensionSettingsHandler::HandleAllowOnAllUrlsMessage(
1160 const base::ListValue* args) {
1161 DCHECK(FeatureSwitch::scripts_require_action()->IsEnabled());
1162 CHECK_EQ(2u, args->GetSize());
1163 std::string extension_id;
1164 std::string allow_str;
1165 CHECK(args->GetString(0, &extension_id));
1166 CHECK(args->GetString(1, &allow_str));
1167 util::SetAllowedScriptingOnAllUrls(extension_id,
1168 extension_service_->GetBrowserContext(),
1169 allow_str == "true");
1172 void ExtensionSettingsHandler::HandleUninstallMessage(
1173 const base::ListValue* args) {
1174 CHECK_EQ(1U, args->GetSize());
1175 std::string extension_id;
1176 CHECK(args->GetString(0, &extension_id));
1177 const Extension* extension =
1178 extension_service_->GetInstalledExtension(extension_id);
1182 if (!management_policy_->UserMayModifySettings(extension, NULL) ||
1183 management_policy_->MustRemainInstalled(extension, NULL)) {
1184 LOG(ERROR) << "An attempt was made to uninstall an extension that is "
1185 << "non-usermanagable. Extension id : " << extension->id();
1189 if (!extension_id_prompting_.empty())
1190 return; // Only one prompt at a time.
1192 extension_id_prompting_ = extension_id;
1194 GetExtensionUninstallDialog()->ConfirmUninstall(extension);
1197 void ExtensionSettingsHandler::HandleOptionsMessage(
1198 const base::ListValue* args) {
1199 const Extension* extension = GetActiveExtension(args);
1200 if (!extension || OptionsPageInfo::GetOptionsPage(extension).is_empty())
1202 ExtensionTabUtil::OpenOptionsPage(extension,
1203 chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()));
1206 void ExtensionSettingsHandler::HandlePermissionsMessage(
1207 const base::ListValue* args) {
1208 std::string extension_id(base::UTF16ToUTF8(ExtractStringValue(args)));
1209 CHECK(!extension_id.empty());
1210 const Extension* extension =
1211 ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))
1212 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
1216 if (!extension_id_prompting_.empty())
1217 return; // Only one prompt at a time.
1218 extension_id_prompting_ = extension->id();
1220 // The BrokerDelegate manages its own lifetime.
1221 BrokerDelegate* broker_delegate = new BrokerDelegate(AsWeakPtr());
1223 // Show the new-style extensions dialog when the flag is set. The flag cannot
1224 // be set on Mac platforms.
1225 if (ShouldDisplayExtensionInfoDialog()) {
1226 UMA_HISTOGRAM_ENUMERATION("Apps.AppInfoDialog.Launches",
1227 AppInfoLaunchSource::FROM_EXTENSIONS_PAGE,
1228 AppInfoLaunchSource::NUM_LAUNCH_SOURCES);
1230 // Display the dialog at a size similar to the app list.
1231 const int kAppInfoDialogWidth = 380;
1232 const int kAppInfoDialogHeight = 490;
1234 ShowAppInfoInNativeDialog(
1235 web_contents()->GetTopLevelNativeWindow(),
1236 gfx::Size(kAppInfoDialogWidth, kAppInfoDialogHeight),
1237 Profile::FromWebUI(web_ui()), extension,
1238 base::Bind(&BrokerDelegate::AppInfoDialogClosed,
1239 base::Unretained(broker_delegate)));
1241 prompt_.reset(new ExtensionInstallPrompt(web_contents()));
1242 std::vector<base::FilePath> retained_file_paths;
1243 if (extension->permissions_data()->HasAPIPermission(
1244 APIPermission::kFileSystem)) {
1245 std::vector<apps::SavedFileEntry> retained_file_entries =
1246 apps::SavedFilesService::Get(Profile::FromWebUI(web_ui()))
1247 ->GetAllFileEntries(extension_id_prompting_);
1248 for (size_t i = 0; i < retained_file_entries.size(); ++i) {
1249 retained_file_paths.push_back(retained_file_entries[i].path);
1252 std::vector<base::string16> retained_device_messages;
1253 if (extension->permissions_data()->HasAPIPermission(APIPermission::kUsb)) {
1254 retained_device_messages =
1255 extensions::DevicePermissionsManager::Get(
1256 Profile::FromWebUI(web_ui()))
1257 ->GetPermissionMessageStrings(extension_id_prompting_);
1260 prompt_->ReviewPermissions(broker_delegate, extension, retained_file_paths,
1261 retained_device_messages);
1265 void ExtensionSettingsHandler::HandleShowButtonMessage(
1266 const base::ListValue* args) {
1267 const Extension* extension = GetActiveExtension(args);
1270 ExtensionActionAPI::SetBrowserActionVisibility(
1271 ExtensionPrefs::Get(extension_service_->profile()),
1276 void ExtensionSettingsHandler::HandleAutoUpdateMessage(
1277 const base::ListValue* args) {
1278 ExtensionUpdater* updater = extension_service_->updater();
1280 ExtensionUpdater::CheckParams params;
1281 params.install_immediately = true;
1282 updater->CheckNow(params);
1286 void ExtensionSettingsHandler::HandleDismissADTPromoMessage(
1287 const base::ListValue* args) {
1288 DCHECK(args->empty());
1289 Profile::FromWebUI(web_ui())->GetPrefs()->SetBoolean(
1290 prefs::kExtensionsUIDismissedADTPromo, true);
1293 void ExtensionSettingsHandler::HandleShowPath(const base::ListValue* args) {
1294 DCHECK(!args->empty());
1295 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1297 Profile* profile = Profile::FromWebUI(web_ui());
1298 ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
1299 const Extension* extension = registry->GetExtensionById(
1301 ExtensionRegistry::EVERYTHING);
1303 // We explicitly show manifest.json in order to work around an issue in OSX
1304 // where opening the directory doesn't focus the Finder.
1305 platform_util::ShowItemInFolder(profile,
1306 extension->path().Append(kManifestFilename));
1309 void ExtensionSettingsHandler::ShowAlert(const std::string& message) {
1310 base::ListValue arguments;
1311 arguments.Append(new base::StringValue(message));
1312 web_ui()->CallJavascriptFunction("alert", arguments);
1315 const Extension* ExtensionSettingsHandler::GetActiveExtension(
1316 const base::ListValue* args) {
1317 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1318 CHECK(!extension_id.empty());
1319 return extension_service_->GetExtensionById(extension_id, false);
1322 void ExtensionSettingsHandler::MaybeUpdateAfterNotification() {
1323 WebContents* contents = web_ui()->GetWebContents();
1324 if (!ignore_notifications_ && contents && contents->GetRenderViewHost())
1325 HandleRequestExtensionsData(NULL);
1326 deleting_rvh_ = NULL;
1329 void ExtensionSettingsHandler::MaybeRegisterForNotifications() {
1330 if (registered_for_notifications_)
1333 registered_for_notifications_ = true;
1334 Profile* profile = Profile::FromWebUI(web_ui());
1336 // Register for notifications that we need to reload the page.
1337 registrar_.Add(this,
1338 extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
1339 content::Source<Profile>(profile));
1340 registrar_.Add(this,
1341 extensions::NOTIFICATION_EXTENSION_HOST_CREATED,
1342 content::NotificationService::AllBrowserContextsAndSources());
1343 registrar_.Add(this,
1344 chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
1345 content::NotificationService::AllBrowserContextsAndSources());
1346 registrar_.Add(this,
1347 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
1348 content::NotificationService::AllBrowserContextsAndSources());
1351 extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
1352 content::Source<ExtensionPrefs>(ExtensionPrefs::Get(profile)));
1353 registrar_.Add(this,
1354 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
1355 content::NotificationService::AllBrowserContextsAndSources());
1356 registrar_.Add(this,
1357 content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
1358 content::NotificationService::AllBrowserContextsAndSources());
1360 extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
1362 content::WebContentsObserver::Observe(web_ui()->GetWebContents());
1364 warning_service_observer_.Add(WarningService::Get(profile));
1366 error_console_observer_.Add(ErrorConsole::Get(profile));
1368 extension_management_observer_.Add(
1369 ExtensionManagementFactory::GetForBrowserContext(profile));
1372 std::vector<ExtensionPage>
1373 ExtensionSettingsHandler::GetInspectablePagesForExtension(
1374 const Extension* extension, bool extension_is_enabled) {
1375 std::vector<ExtensionPage> result;
1377 // Get the extension process's active views.
1378 extensions::ProcessManager* process_manager =
1379 ProcessManager::Get(extension_service_->profile());
1380 GetInspectablePagesForExtensionProcess(
1382 process_manager->GetRenderViewHostsForExtension(extension->id()),
1385 // Get app window views
1386 GetAppWindowPagesForExtensionProfile(
1387 extension, extension_service_->profile(), &result);
1389 // Include a link to start the lazy background page, if applicable.
1390 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
1391 extension_is_enabled &&
1392 !process_manager->GetBackgroundHostForExtension(extension->id())) {
1393 result.push_back(ExtensionPage(
1394 BackgroundInfo::GetBackgroundURL(extension),
1398 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
1401 // Repeat for the incognito process, if applicable. Don't try to get
1402 // app windows for incognito processes.
1403 if (extension_service_->profile()->HasOffTheRecordProfile() &&
1404 IncognitoInfo::IsSplitMode(extension) &&
1405 util::IsIncognitoEnabled(extension->id(),
1406 extension_service_->profile())) {
1407 extensions::ProcessManager* process_manager = ProcessManager::Get(
1408 extension_service_->profile()->GetOffTheRecordProfile());
1409 GetInspectablePagesForExtensionProcess(
1411 process_manager->GetRenderViewHostsForExtension(extension->id()),
1414 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
1415 extension_is_enabled &&
1416 !process_manager->GetBackgroundHostForExtension(extension->id())) {
1417 result.push_back(ExtensionPage(
1418 BackgroundInfo::GetBackgroundURL(extension),
1422 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
1429 void ExtensionSettingsHandler::GetInspectablePagesForExtensionProcess(
1430 const Extension* extension,
1431 const std::set<RenderViewHost*>& views,
1432 std::vector<ExtensionPage>* result) {
1433 bool has_generated_background_page =
1434 BackgroundInfo::HasGeneratedBackgroundPage(extension);
1435 for (std::set<RenderViewHost*>::const_iterator iter = views.begin();
1436 iter != views.end(); ++iter) {
1437 RenderViewHost* host = *iter;
1438 WebContents* web_contents = WebContents::FromRenderViewHost(host);
1439 ViewType host_type = GetViewType(web_contents);
1440 if (host == deleting_rvh_ ||
1441 VIEW_TYPE_EXTENSION_POPUP == host_type ||
1442 VIEW_TYPE_EXTENSION_DIALOG == host_type)
1445 GURL url = web_contents->GetURL();
1446 content::RenderProcessHost* process = host->GetProcess();
1447 bool is_background_page =
1448 (url == BackgroundInfo::GetBackgroundURL(extension));
1452 host->GetRoutingID(),
1453 process->GetBrowserContext()->IsOffTheRecord(),
1454 is_background_page && has_generated_background_page));
1458 void ExtensionSettingsHandler::GetAppWindowPagesForExtensionProfile(
1459 const Extension* extension,
1461 std::vector<ExtensionPage>* result) {
1462 AppWindowRegistry* registry = AppWindowRegistry::Get(profile);
1463 if (!registry) return;
1465 const AppWindowRegistry::AppWindowList windows =
1466 registry->GetAppWindowsForApp(extension->id());
1468 bool has_generated_background_page =
1469 BackgroundInfo::HasGeneratedBackgroundPage(extension);
1470 for (AppWindowRegistry::const_iterator it = windows.begin();
1471 it != windows.end();
1473 WebContents* web_contents = (*it)->web_contents();
1474 RenderViewHost* host = web_contents->GetRenderViewHost();
1475 content::RenderProcessHost* process = host->GetProcess();
1477 bool is_background_page =
1478 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
1480 ExtensionPage(web_contents->GetURL(),
1482 host->GetRoutingID(),
1483 process->GetBrowserContext()->IsOffTheRecord(),
1484 is_background_page && has_generated_background_page));
1488 ExtensionUninstallDialog*
1489 ExtensionSettingsHandler::GetExtensionUninstallDialog() {
1490 if (!extension_uninstall_dialog_.get()) {
1491 Browser* browser = chrome::FindBrowserWithWebContents(
1492 web_ui()->GetWebContents());
1493 extension_uninstall_dialog_.reset(
1494 ExtensionUninstallDialog::Create(extension_service_->profile(),
1495 browser->window()->GetNativeWindow(),
1498 return extension_uninstall_dialog_.get();
1501 void ExtensionSettingsHandler::OnReinstallComplete(
1503 const std::string& error,
1504 webstore_install::Result result) {
1505 MaybeUpdateAfterNotification();
1508 void ExtensionSettingsHandler::OnRequirementsChecked(
1509 std::string extension_id,
1510 std::vector<std::string> requirement_errors) {
1511 if (requirement_errors.empty()) {
1512 extension_service_->EnableExtension(extension_id);
1514 ExtensionErrorReporter::GetInstance()->ReportError(
1515 base::UTF8ToUTF16(JoinString(requirement_errors, ' ')),
1518 requirements_checker_.reset();
1521 } // namespace extensions