Move manifest_url_handler to //extensions
[chromium-blink-merge.git] / chrome / browser / ui / webui / extensions / extension_settings_handler.cc
blob0e73bc834207f0747fbcc616f8f44d7a5c7cfaef
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;
110 namespace {
111 const char kAppsDeveloperToolsExtensionId[] =
112 "ohmmkhmmmpcnpikjeljgnaoabkaalbgc";
115 namespace extensions {
117 ExtensionPage::ExtensionPage(const GURL& url,
118 int render_process_id,
119 int render_view_id,
120 bool incognito,
121 bool generated_background_page)
122 : url(url),
123 render_process_id(render_process_id),
124 render_view_id(render_view_id),
125 incognito(incognito),
126 generated_background_page(generated_background_page) {
129 // On Mac, the install prompt is not modal. This means that the user can
130 // navigate while the dialog is up, causing the dialog handler to outlive the
131 // ExtensionSettingsHandler. That's a problem because the dialog framework will
132 // try to contact us back once the dialog is closed, which causes a crash.
133 // This class is designed to broker the message between the two objects, while
134 // managing its own lifetime so that it can outlive the ExtensionSettingsHandler
135 // and (when doing so) gracefully ignore the message from the dialog.
136 class BrokerDelegate : public ExtensionInstallPrompt::Delegate {
137 public:
138 explicit BrokerDelegate(
139 const base::WeakPtr<ExtensionSettingsHandler>& delegate)
140 : delegate_(delegate) {}
142 // ExtensionInstallPrompt::Delegate implementation.
143 virtual void InstallUIProceed() override {
144 if (delegate_)
145 delegate_->InstallUIProceed();
146 delete this;
149 virtual void InstallUIAbort(bool user_initiated) override {
150 if (delegate_)
151 delegate_->InstallUIAbort(user_initiated);
152 delete this;
155 private:
156 base::WeakPtr<ExtensionSettingsHandler> delegate_;
158 DISALLOW_COPY_AND_ASSIGN(BrokerDelegate);
161 ///////////////////////////////////////////////////////////////////////////////
163 // ExtensionSettingsHandler
165 ///////////////////////////////////////////////////////////////////////////////
167 ExtensionSettingsHandler::ExtensionSettingsHandler()
168 : extension_service_(NULL),
169 management_policy_(NULL),
170 ignore_notifications_(false),
171 deleting_rvh_(NULL),
172 deleting_rwh_id_(-1),
173 deleting_rph_id_(-1),
174 registered_for_notifications_(false),
175 warning_service_observer_(this),
176 error_console_observer_(this),
177 extension_prefs_observer_(this),
178 extension_registry_observer_(this),
179 extension_management_observer_(this),
180 should_do_verification_check_(false) {
183 ExtensionSettingsHandler::~ExtensionSettingsHandler() {
186 ExtensionSettingsHandler::ExtensionSettingsHandler(ExtensionService* service,
187 ManagementPolicy* policy)
188 : extension_service_(service),
189 management_policy_(policy),
190 ignore_notifications_(false),
191 deleting_rvh_(NULL),
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 // static
204 void ExtensionSettingsHandler::RegisterProfilePrefs(
205 user_prefs::PrefRegistrySyncable* registry) {
206 registry->RegisterBooleanPref(
207 prefs::kExtensionsUIDeveloperMode,
208 false,
209 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
210 registry->RegisterBooleanPref(
211 prefs::kExtensionsUIDismissedADTPromo,
212 false,
213 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
216 base::DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue(
217 const Extension* extension,
218 const std::vector<ExtensionPage>& pages,
219 const WarningService* warning_service) {
220 // The items which are to be written into app_dict are also described in
221 // chrome/browser/resources/extensions/extension_list.js in @typedef for
222 // ExtensionData. Please update it whenever you add or remove any keys here.
223 base::DictionaryValue* extension_data = new base::DictionaryValue();
224 bool enabled = extension_service_->IsExtensionEnabled(extension->id());
225 GetExtensionBasicInfo(extension, enabled, extension_data);
227 ExtensionPrefs* prefs = ExtensionPrefs::Get(extension_service_->profile());
228 int disable_reasons = prefs->GetDisableReasons(extension->id());
230 bool suspicious_install =
231 (disable_reasons & Extension::DISABLE_NOT_VERIFIED) != 0;
232 extension_data->SetBoolean("suspiciousInstall", suspicious_install);
233 if (suspicious_install)
234 should_do_verification_check_ = true;
236 bool corrupt_install =
237 (disable_reasons & Extension::DISABLE_CORRUPTED) != 0;
238 extension_data->SetBoolean("corruptInstall", corrupt_install);
240 bool managed_install =
241 !management_policy_->UserMayModifySettings(extension, NULL);
242 extension_data->SetBoolean("managedInstall", managed_install);
244 bool recommended_install =
245 !managed_install &&
246 management_policy_->MustRemainInstalled(extension, NULL);
247 extension_data->SetBoolean("recommendedInstall", recommended_install);
249 // Suspicious install should always be mutually exclusive to managed and/or
250 // recommended install.
251 DCHECK(!(managed_install || recommended_install) || !suspicious_install);
253 GURL icon =
254 ExtensionIconSource::GetIconURL(extension,
255 extension_misc::EXTENSION_ICON_MEDIUM,
256 ExtensionIconSet::MATCH_BIGGER,
257 !enabled, NULL);
258 if (Manifest::IsUnpackedLocation(extension->location())) {
259 extension_data->SetString("path", extension->path().value());
260 extension_data->SetString(
261 "prettifiedPath",
262 extensions::path_util::PrettifyPath(extension->path()).value());
264 extension_data->SetString("icon", icon.spec());
265 extension_data->SetBoolean("isUnpacked",
266 Manifest::IsUnpackedLocation(extension->location()));
267 extension_data->SetBoolean("isFromStore",
268 extension->location() == Manifest::INTERNAL &&
269 ManifestURL::UpdatesFromGallery(extension));
270 ExtensionRegistry* registry =
271 ExtensionRegistry::Get(extension_service_->profile());
272 extension_data->SetBoolean(
273 "terminated",
274 registry->terminated_extensions().Contains(extension->id()));
275 extension_data->SetBoolean("enabledIncognito",
276 util::IsIncognitoEnabled(extension->id(), extension_service_->profile()));
277 extension_data->SetBoolean("incognitoCanBeEnabled",
278 extension->can_be_incognito_enabled());
279 extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access());
280 extension_data->SetBoolean("allowFileAccess",
281 util::AllowFileAccess(extension->id(), extension_service_->profile()));
282 extension_data->SetBoolean("allow_reload",
283 Manifest::IsUnpackedLocation(extension->location()));
284 extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app());
285 extension_data->SetBoolean("is_platform_app", extension->is_platform_app());
286 extension_data->SetBoolean("homepageProvided",
287 ManifestURL::SpecifiedHomepageURL(extension));
288 extension_data->SetBoolean("optionsOpenInTab",
289 OptionsPageInfo::ShouldOpenInTab(extension));
291 // Add dependent extensions.
292 base::ListValue* dependents_list = new base::ListValue;
293 if (extension->is_shared_module()) {
294 scoped_ptr<ExtensionSet> dependent_extensions =
295 extension_service_->shared_module_service()->GetDependentExtensions(
296 extension);
297 for (ExtensionSet::const_iterator i = dependent_extensions->begin();
298 i != dependent_extensions->end();
299 i++) {
300 base::DictionaryValue* dependent_entry = new base::DictionaryValue;
301 dependent_entry->SetString("id", (*i)->id());
302 dependent_entry->SetString("name", (*i)->name());
303 dependents_list->Append(dependent_entry);
306 extension_data->Set("dependentExtensions", dependents_list);
308 // Extensions only want all URL access if:
309 // - The feature is enabled for the given extension.
310 // - The extension has access to enough urls that we can't just let it run
311 // on those specified in the permissions.
312 bool wants_all_urls =
313 util::ScriptsMayRequireActionForExtension(extension) &&
314 (extension->permissions_data()->HasWithheldImpliedAllHosts() ||
315 util::AllowedScriptingOnAllUrls(
316 extension->id(), extension_service_->GetBrowserContext()));
317 extension_data->SetBoolean("wantsAllUrls", wants_all_urls);
318 extension_data->SetBoolean(
319 "allowAllUrls",
320 util::AllowedScriptingOnAllUrls(
321 extension->id(),
322 extension_service_->GetBrowserContext()));
324 base::string16 location_text;
325 if (Manifest::IsPolicyLocation(extension->location()) ||
326 (extension->location() == Manifest::EXTERNAL_PREF_DOWNLOAD &&
327 recommended_install)) {
328 location_text = l10n_util::GetStringUTF16(
329 IDS_OPTIONS_INSTALL_LOCATION_ENTERPRISE);
330 } else if (extension->location() == Manifest::INTERNAL &&
331 !ManifestURL::UpdatesFromGallery(extension)) {
332 location_text = l10n_util::GetStringUTF16(
333 IDS_OPTIONS_INSTALL_LOCATION_UNKNOWN);
334 } else if (extension->location() == Manifest::EXTERNAL_REGISTRY) {
335 location_text = l10n_util::GetStringUTF16(
336 IDS_OPTIONS_INSTALL_LOCATION_3RD_PARTY);
337 } else if (extension->is_shared_module()) {
338 location_text = l10n_util::GetStringUTF16(
339 IDS_OPTIONS_INSTALL_LOCATION_SHARED_MODULE);
341 extension_data->SetString("locationText", location_text);
343 base::string16 blacklist_text;
344 switch (prefs->GetExtensionBlacklistState(extension->id())) {
345 case BLACKLISTED_SECURITY_VULNERABILITY:
346 blacklist_text = l10n_util::GetStringUTF16(
347 IDS_OPTIONS_BLACKLISTED_SECURITY_VULNERABILITY);
348 break;
350 case BLACKLISTED_CWS_POLICY_VIOLATION:
351 blacklist_text = l10n_util::GetStringUTF16(
352 IDS_OPTIONS_BLACKLISTED_CWS_POLICY_VIOLATION);
353 break;
355 case BLACKLISTED_POTENTIALLY_UNWANTED:
356 blacklist_text = l10n_util::GetStringUTF16(
357 IDS_OPTIONS_BLACKLISTED_POTENTIALLY_UNWANTED);
358 break;
360 default:
361 break;
363 extension_data->SetString("blacklistText", blacklist_text);
365 // Force unpacked extensions to show at the top.
366 if (Manifest::IsUnpackedLocation(extension->location()))
367 extension_data->SetInteger("order", 1);
368 else
369 extension_data->SetInteger("order", 2);
371 if (!ExtensionActionAPI::GetBrowserActionVisibility(prefs, extension->id())) {
372 extension_data->SetBoolean("enable_show_button", true);
375 // Add views
376 base::ListValue* views = new base::ListValue;
377 for (std::vector<ExtensionPage>::const_iterator iter = pages.begin();
378 iter != pages.end(); ++iter) {
379 base::DictionaryValue* view_value = new base::DictionaryValue;
380 if (iter->url.scheme() == kExtensionScheme) {
381 // No leading slash.
382 view_value->SetString("path", iter->url.path().substr(1));
383 } else {
384 // For live pages, use the full URL.
385 view_value->SetString("path", iter->url.spec());
387 view_value->SetInteger("renderViewId", iter->render_view_id);
388 view_value->SetInteger("renderProcessId", iter->render_process_id);
389 view_value->SetBoolean("incognito", iter->incognito);
390 view_value->SetBoolean("generatedBackgroundPage",
391 iter->generated_background_page);
392 views->Append(view_value);
394 extension_data->Set("views", views);
395 ExtensionActionManager* extension_action_manager =
396 ExtensionActionManager::Get(extension_service_->profile());
397 extension_data->SetBoolean(
398 "hasPopupAction",
399 extension_action_manager->GetBrowserAction(*extension) ||
400 extension_action_manager->GetPageAction(*extension));
402 // Add warnings.
403 if (warning_service) {
404 std::vector<std::string> warnings =
405 warning_service->GetWarningMessagesForExtension(extension->id());
407 if (!warnings.empty()) {
408 base::ListValue* warnings_list = new base::ListValue;
409 for (std::vector<std::string>::const_iterator iter = warnings.begin();
410 iter != warnings.end(); ++iter) {
411 warnings_list->Append(new base::StringValue(*iter));
413 extension_data->Set("warnings", warnings_list);
417 // If the ErrorConsole is enabled and the extension is unpacked, use the more
418 // detailed errors from the ErrorConsole. Otherwise, use the install warnings
419 // (using both is redundant).
420 ErrorConsole* error_console =
421 ErrorConsole::Get(extension_service_->profile());
422 bool error_console_is_enabled =
423 error_console->IsEnabledForChromeExtensionsPage();
424 extension_data->SetBoolean("wantsErrorCollection", error_console_is_enabled);
425 if (error_console_is_enabled) {
426 extension_data->SetBoolean("errorCollectionEnabled",
427 error_console->IsReportingEnabledForExtension(
428 extension->id()));
429 const ErrorList& errors =
430 error_console->GetErrorsForExtension(extension->id());
431 if (!errors.empty()) {
432 scoped_ptr<base::ListValue> manifest_errors(new base::ListValue);
433 scoped_ptr<base::ListValue> runtime_errors(new base::ListValue);
434 for (ErrorList::const_iterator iter = errors.begin();
435 iter != errors.end(); ++iter) {
436 if ((*iter)->type() == ExtensionError::MANIFEST_ERROR) {
437 manifest_errors->Append((*iter)->ToValue().release());
438 } else { // Handle runtime error.
439 const RuntimeError* error = static_cast<const RuntimeError*>(*iter);
440 scoped_ptr<base::DictionaryValue> value = error->ToValue();
441 bool can_inspect =
442 !(deleting_rwh_id_ == error->render_view_id() &&
443 deleting_rph_id_ == error->render_process_id()) &&
444 RenderViewHost::FromID(error->render_process_id(),
445 error->render_view_id()) != NULL;
446 value->SetBoolean("canInspect", can_inspect);
447 runtime_errors->Append(value.release());
450 if (!manifest_errors->empty())
451 extension_data->Set("manifestErrors", manifest_errors.release());
452 if (!runtime_errors->empty())
453 extension_data->Set("runtimeErrors", runtime_errors.release());
455 } else if (Manifest::IsUnpackedLocation(extension->location())) {
456 const std::vector<InstallWarning>& install_warnings =
457 extension->install_warnings();
458 if (!install_warnings.empty()) {
459 scoped_ptr<base::ListValue> list(new base::ListValue());
460 for (std::vector<InstallWarning>::const_iterator it =
461 install_warnings.begin(); it != install_warnings.end(); ++it) {
462 base::DictionaryValue* item = new base::DictionaryValue();
463 item->SetString("message", it->message);
464 list->Append(item);
466 extension_data->Set("installWarnings", list.release());
470 return extension_data;
473 void ExtensionSettingsHandler::GetLocalizedValues(
474 content::WebUIDataSource* source) {
475 source->AddString("extensionSettings",
476 l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE));
478 source->AddString("extensionSettingsDeveloperMode",
479 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK));
480 source->AddString("extensionSettingsNoExtensions",
481 l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED));
482 source->AddString(
483 "extensionSettingsSuggestGallery",
484 l10n_util::GetStringFUTF16(
485 IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY,
486 base::ASCIIToUTF16(
487 google_util::AppendGoogleLocaleParam(
488 GURL(extension_urls::GetWebstoreExtensionsCategoryURL()),
489 g_browser_process->GetApplicationLocale()).spec())));
490 source->AddString("extensionSettingsGetMoreExtensions",
491 l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS));
492 source->AddString(
493 "extensionSettingsGetMoreExtensionsUrl",
494 base::ASCIIToUTF16(
495 google_util::AppendGoogleLocaleParam(
496 GURL(extension_urls::GetWebstoreExtensionsCategoryURL()),
497 g_browser_process->GetApplicationLocale()).spec()));
498 source->AddString("extensionSettingsExtensionId",
499 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID));
500 source->AddString("extensionSettingsExtensionPath",
501 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PATH));
502 source->AddString("extensionSettingsInspectViews",
503 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS));
504 source->AddString("extensionSettingsInstallWarnings",
505 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALL_WARNINGS));
506 source->AddString("viewIncognito",
507 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO));
508 source->AddString("viewInactive",
509 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INACTIVE));
510 source->AddString("backgroundPage",
511 l10n_util::GetStringUTF16(IDS_EXTENSIONS_BACKGROUND_PAGE));
512 source->AddString("extensionSettingsEnable",
513 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE));
514 source->AddString("extensionSettingsEnabled",
515 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLED));
516 source->AddString("extensionSettingsRemove",
517 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REMOVE));
518 source->AddString("extensionSettingsEnableIncognito",
519 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO));
520 source->AddString("extensionSettingsEnableErrorCollection",
521 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_ERROR_COLLECTION));
522 source->AddString("extensionSettingsAllowFileAccess",
523 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS));
524 source->AddString("extensionSettingsAllowOnAllUrls",
525 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_ON_ALL_URLS));
526 source->AddString("extensionSettingsIncognitoWarning",
527 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING));
528 source->AddString("extensionSettingsReloadTerminated",
529 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_TERMINATED));
530 source->AddString("extensionSettingsRepairCorrupted",
531 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REPAIR_CORRUPTED));
532 source->AddString("extensionSettingsLaunch",
533 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LAUNCH));
534 source->AddString("extensionSettingsReloadUnpacked",
535 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_UNPACKED));
536 source->AddString("extensionSettingsOptions",
537 l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS_LINK));
538 if (CommandLine::ForCurrentProcess()->HasSwitch(
539 switches::kEnableExtensionInfoDialog)) {
540 source->AddString("extensionSettingsPermissions",
541 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INFO_LINK));
542 } else {
543 source->AddString(
544 "extensionSettingsPermissions",
545 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PERMISSIONS_LINK));
547 source->AddString("extensionSettingsVisitWebsite",
548 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSITE));
549 source->AddString("extensionSettingsVisitWebStore",
550 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSTORE));
551 source->AddString("extensionSettingsPolicyControlled",
552 l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED));
553 source->AddString("extensionSettingsPolicyRecommeneded",
554 l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_RECOMMENDED));
555 source->AddString("extensionSettingsDependentExtensions",
556 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEPENDENT_EXTENSIONS));
557 source->AddString("extensionSettingsSupervisedUser",
558 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_SUPERVISED_USER));
559 source->AddString("extensionSettingsCorruptInstall",
560 l10n_util::GetStringUTF16(
561 IDS_EXTENSIONS_CORRUPTED_EXTENSION));
562 source->AddString("extensionSettingsSuspiciousInstall",
563 l10n_util::GetStringFUTF16(
564 IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE,
565 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)));
566 source->AddString("extensionSettingsLearnMore",
567 l10n_util::GetStringUTF16(IDS_LEARN_MORE));
568 source->AddString("extensionSettingsSuspiciousInstallHelpUrl",
569 base::ASCIIToUTF16(
570 google_util::AppendGoogleLocaleParam(
571 GURL(chrome::kRemoveNonCWSExtensionURL),
572 g_browser_process->GetApplicationLocale()).spec()));
573 source->AddString("extensionSettingsShowButton",
574 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON));
575 source->AddString("extensionSettingsLoadUnpackedButton",
576 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON));
577 source->AddString("extensionSettingsPackButton",
578 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON));
579 source->AddString("extensionSettingsCommandsLink",
580 l10n_util::GetStringUTF16(IDS_EXTENSIONS_COMMANDS_CONFIGURE));
581 source->AddString("extensionSettingsUpdateButton",
582 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON));
583 source->AddString(
584 "extensionSettingsAppsDevToolsPromoHTML",
585 l10n_util::GetStringFUTF16(
586 IDS_EXTENSIONS_APPS_DEV_TOOLS_PROMO_HTML,
587 base::ASCIIToUTF16(
588 google_util::AppendGoogleLocaleParam(
589 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() +
590 kAppsDeveloperToolsExtensionId),
591 g_browser_process->GetApplicationLocale()).spec())));
592 source->AddString(
593 "extensionSettingsAppDevToolsPromoClose",
594 l10n_util::GetStringUTF16(IDS_CLOSE));
595 source->AddString("extensionSettingsCrashMessage",
596 l10n_util::GetStringUTF16(IDS_EXTENSIONS_CRASHED_EXTENSION));
597 source->AddString("extensionSettingsInDevelopment",
598 l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT));
599 source->AddString("extensionSettingsWarningsTitle",
600 l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_TITLE));
601 source->AddString("extensionSettingsShowDetails",
602 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS));
603 source->AddString("extensionSettingsHideDetails",
604 l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS));
606 // TODO(estade): comb through the above strings to find ones no longer used in
607 // uber extensions.
608 source->AddString("extensionUninstall",
609 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
612 void ExtensionSettingsHandler::RenderViewDeleted(
613 RenderViewHost* render_view_host) {
614 deleting_rvh_ = render_view_host;
615 Profile* source_profile = Profile::FromBrowserContext(
616 render_view_host->GetSiteInstance()->GetBrowserContext());
617 if (!Profile::FromWebUI(web_ui())->IsSameProfile(source_profile))
618 return;
619 MaybeUpdateAfterNotification();
622 void ExtensionSettingsHandler::DidStartNavigationToPendingEntry(
623 const GURL& url,
624 content::NavigationController::ReloadType reload_type) {
625 if (reload_type != content::NavigationController::NO_RELOAD)
626 ReloadUnpackedExtensions();
629 void ExtensionSettingsHandler::RegisterMessages() {
630 // Don't override an |extension_service_| or |management_policy_| injected
631 // for testing.
632 if (!extension_service_) {
633 Profile* profile = Profile::FromWebUI(web_ui())->GetOriginalProfile();
634 extension_service_ =
635 extensions::ExtensionSystem::Get(profile)->extension_service();
637 if (!management_policy_) {
638 management_policy_ = ExtensionSystem::Get(
639 extension_service_->profile())->management_policy();
642 web_ui()->RegisterMessageCallback("extensionSettingsRequestExtensionsData",
643 base::Bind(&ExtensionSettingsHandler::HandleRequestExtensionsData,
644 AsWeakPtr()));
645 web_ui()->RegisterMessageCallback("extensionSettingsToggleDeveloperMode",
646 base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode,
647 AsWeakPtr()));
648 web_ui()->RegisterMessageCallback("extensionSettingsInspect",
649 base::Bind(&ExtensionSettingsHandler::HandleInspectMessage,
650 AsWeakPtr()));
651 web_ui()->RegisterMessageCallback("extensionSettingsLaunch",
652 base::Bind(&ExtensionSettingsHandler::HandleLaunchMessage,
653 AsWeakPtr()));
654 web_ui()->RegisterMessageCallback("extensionSettingsReload",
655 base::Bind(&ExtensionSettingsHandler::HandleReloadMessage,
656 AsWeakPtr()));
657 web_ui()->RegisterMessageCallback("extensionSettingsRepair",
658 base::Bind(&ExtensionSettingsHandler::HandleRepairMessage,
659 AsWeakPtr()));
660 web_ui()->RegisterMessageCallback("extensionSettingsEnable",
661 base::Bind(&ExtensionSettingsHandler::HandleEnableMessage,
662 AsWeakPtr()));
663 web_ui()->RegisterMessageCallback("extensionSettingsEnableIncognito",
664 base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage,
665 AsWeakPtr()));
666 web_ui()->RegisterMessageCallback("extensionSettingsEnableErrorCollection",
667 base::Bind(&ExtensionSettingsHandler::HandleEnableErrorCollectionMessage,
668 AsWeakPtr()));
669 web_ui()->RegisterMessageCallback("extensionSettingsAllowFileAccess",
670 base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage,
671 AsWeakPtr()));
672 web_ui()->RegisterMessageCallback("extensionSettingsAllowOnAllUrls",
673 base::Bind(&ExtensionSettingsHandler::HandleAllowOnAllUrlsMessage,
674 AsWeakPtr()));
675 web_ui()->RegisterMessageCallback("extensionSettingsUninstall",
676 base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage,
677 AsWeakPtr()));
678 web_ui()->RegisterMessageCallback("extensionSettingsOptions",
679 base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage,
680 AsWeakPtr()));
681 web_ui()->RegisterMessageCallback("extensionSettingsPermissions",
682 base::Bind(&ExtensionSettingsHandler::HandlePermissionsMessage,
683 AsWeakPtr()));
684 web_ui()->RegisterMessageCallback("extensionSettingsShowButton",
685 base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage,
686 AsWeakPtr()));
687 web_ui()->RegisterMessageCallback("extensionSettingsAutoupdate",
688 base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage,
689 AsWeakPtr()));
690 web_ui()->RegisterMessageCallback("extensionSettingsDismissADTPromo",
691 base::Bind(&ExtensionSettingsHandler::HandleDismissADTPromoMessage,
692 AsWeakPtr()));
693 web_ui()->RegisterMessageCallback("extensionSettingsShowPath",
694 base::Bind(&ExtensionSettingsHandler::HandleShowPath,
695 AsWeakPtr()));
698 void ExtensionSettingsHandler::OnErrorAdded(const ExtensionError* error) {
699 MaybeUpdateAfterNotification();
702 void ExtensionSettingsHandler::Observe(
703 int type,
704 const content::NotificationSource& source,
705 const content::NotificationDetails& details) {
706 Profile* profile = Profile::FromWebUI(web_ui());
707 Profile* source_profile = NULL;
708 switch (type) {
709 // We listen for notifications that will result in the page being
710 // repopulated with data twice for the same event in certain cases.
711 // For instance, EXTENSION_LOADED & EXTENSION_HOST_CREATED because
712 // we don't know about the views for an extension at EXTENSION_LOADED, but
713 // if we only listen to EXTENSION_HOST_CREATED, we'll miss extensions
714 // that don't have a process at startup.
716 // Doing it this way gets everything but causes the page to be rendered
717 // more than we need. It doesn't seem to result in any noticeable flicker.
718 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED:
719 deleting_rvh_ = content::Details<BackgroundContents>(details)->
720 web_contents()->GetRenderViewHost();
721 // Fall through.
722 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED:
723 case extensions::NOTIFICATION_EXTENSION_HOST_CREATED:
724 source_profile = content::Source<Profile>(source).ptr();
725 if (!profile->IsSameProfile(source_profile))
726 return;
727 MaybeUpdateAfterNotification();
728 break;
729 case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
730 content::RenderWidgetHost* rwh =
731 content::Source<content::RenderWidgetHost>(source).ptr();
732 deleting_rwh_id_ = rwh->GetRoutingID();
733 deleting_rph_id_ = rwh->GetProcess()->GetID();
734 MaybeUpdateAfterNotification();
735 break;
737 case extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED:
738 case extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED:
739 MaybeUpdateAfterNotification();
740 break;
741 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED:
742 // This notification is sent when the extension host destruction begins,
743 // not when it finishes. We use PostTask to delay the update until after
744 // the destruction finishes.
745 base::MessageLoop::current()->PostTask(
746 FROM_HERE,
747 base::Bind(&ExtensionSettingsHandler::MaybeUpdateAfterNotification,
748 AsWeakPtr()));
749 break;
750 default:
751 NOTREACHED();
755 void ExtensionSettingsHandler::OnExtensionLoaded(
756 content::BrowserContext* browser_context,
757 const Extension* extension) {
758 MaybeUpdateAfterNotification();
761 void ExtensionSettingsHandler::OnExtensionUnloaded(
762 content::BrowserContext* browser_context,
763 const Extension* extension,
764 UnloadedExtensionInfo::Reason reason) {
765 MaybeUpdateAfterNotification();
768 void ExtensionSettingsHandler::OnExtensionUninstalled(
769 content::BrowserContext* browser_context,
770 const Extension* extension,
771 extensions::UninstallReason reason) {
772 MaybeUpdateAfterNotification();
775 void ExtensionSettingsHandler::OnExtensionDisableReasonsChanged(
776 const std::string& extension_id, int disable_reasons) {
777 MaybeUpdateAfterNotification();
780 void ExtensionSettingsHandler::OnExtensionManagementSettingsChanged() {
781 MaybeUpdateAfterNotification();
784 void ExtensionSettingsHandler::ExtensionUninstallAccepted() {
785 DCHECK(!extension_id_prompting_.empty());
787 bool was_terminated = false;
789 // The extension can be uninstalled in another window while the UI was
790 // showing. Do nothing in that case.
791 const Extension* extension =
792 extension_service_->GetExtensionById(extension_id_prompting_, true);
793 if (!extension) {
794 extension =
795 ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))->GetExtensionById(
796 extension_id_prompting_, ExtensionRegistry::TERMINATED);
797 was_terminated = true;
799 if (!extension)
800 return;
802 extension_service_->UninstallExtension(
803 extension_id_prompting_,
804 extensions::UNINSTALL_REASON_USER_INITIATED,
805 base::Bind(&base::DoNothing),
806 NULL); // Error.
807 extension_id_prompting_ = "";
809 // There will be no EXTENSION_UNLOADED notification for terminated
810 // extensions as they were already unloaded.
811 if (was_terminated)
812 HandleRequestExtensionsData(NULL);
815 void ExtensionSettingsHandler::ExtensionUninstallCanceled() {
816 extension_id_prompting_ = "";
819 void ExtensionSettingsHandler::ExtensionWarningsChanged() {
820 MaybeUpdateAfterNotification();
823 // This is called when the user clicks "Revoke File/Device Access."
824 void ExtensionSettingsHandler::InstallUIProceed() {
825 Profile* profile = Profile::FromWebUI(web_ui());
826 extensions::DevicePermissionsManager::Get(profile)
827 ->Clear(extension_id_prompting_);
828 apps::SavedFilesService::Get(profile)->ClearQueue(
829 extension_service_->GetExtensionById(extension_id_prompting_, true));
830 apps::AppLoadService::Get(profile)
831 ->RestartApplicationIfRunning(extension_id_prompting_);
832 extension_id_prompting_.clear();
835 void ExtensionSettingsHandler::InstallUIAbort(bool user_initiated) {
836 extension_id_prompting_.clear();
839 void ExtensionSettingsHandler::AppInfoDialogClosed() {
840 extension_id_prompting_.clear();
843 void ExtensionSettingsHandler::ReloadUnpackedExtensions() {
844 const ExtensionSet* extensions = extension_service_->extensions();
845 std::vector<const Extension*> unpacked_extensions;
846 for (ExtensionSet::const_iterator extension = extensions->begin();
847 extension != extensions->end(); ++extension) {
848 if (Manifest::IsUnpackedLocation((*extension)->location()))
849 unpacked_extensions.push_back(extension->get());
852 for (std::vector<const Extension*>::iterator iter =
853 unpacked_extensions.begin(); iter != unpacked_extensions.end(); ++iter) {
854 extension_service_->ReloadExtensionWithQuietFailure((*iter)->id());
858 void ExtensionSettingsHandler::HandleRequestExtensionsData(
859 const base::ListValue* args) {
860 // The items which are to be written into results are also described in
861 // chrome/browser/resources/extensions/extensions.js in @typedef for
862 // ExtensionDataResponse. Please update it whenever you add or remove any keys
863 // here.
864 base::DictionaryValue results;
866 Profile* profile = Profile::FromWebUI(web_ui());
868 // Add the extensions to the results structure.
869 base::ListValue* extensions_list = new base::ListValue();
871 WarningService* warnings = ExtensionSystem::Get(profile)->warning_service();
873 ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
874 const ExtensionSet& enabled_set = registry->enabled_extensions();
875 for (ExtensionSet::const_iterator extension = enabled_set.begin();
876 extension != enabled_set.end(); ++extension) {
877 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) {
878 extensions_list->Append(CreateExtensionDetailValue(
879 extension->get(),
880 GetInspectablePagesForExtension(extension->get(), true),
881 warnings));
884 const ExtensionSet& disabled_set = registry->disabled_extensions();
885 for (ExtensionSet::const_iterator extension = disabled_set.begin();
886 extension != disabled_set.end(); ++extension) {
887 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) {
888 extensions_list->Append(CreateExtensionDetailValue(
889 extension->get(),
890 GetInspectablePagesForExtension(extension->get(), false),
891 warnings));
894 const ExtensionSet& terminated_set = registry->terminated_extensions();
895 std::vector<ExtensionPage> empty_pages;
896 for (ExtensionSet::const_iterator extension = terminated_set.begin();
897 extension != terminated_set.end(); ++extension) {
898 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) {
899 extensions_list->Append(CreateExtensionDetailValue(
900 extension->get(),
901 empty_pages, // Terminated process has no active pages.
902 warnings));
905 results.Set("extensions", extensions_list);
907 bool is_supervised = profile->IsSupervised();
908 bool incognito_available =
909 IncognitoModePrefs::GetAvailability(profile->GetPrefs()) !=
910 IncognitoModePrefs::DISABLED;
911 bool developer_mode =
912 !is_supervised &&
913 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
914 results.SetBoolean("profileIsSupervised", is_supervised);
915 results.SetBoolean("incognitoAvailable", incognito_available);
916 results.SetBoolean("developerMode", developer_mode);
918 // Promote the Chrome Apps & Extensions Developer Tools if they are not
919 // installed and the user has not previously dismissed the warning.
920 bool promote_apps_dev_tools = false;
921 if (!ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))->
922 GetExtensionById(kAppsDeveloperToolsExtensionId,
923 ExtensionRegistry::EVERYTHING) &&
924 !profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDismissedADTPromo)) {
925 promote_apps_dev_tools = true;
927 results.SetBoolean("promoteAppsDevTools", promote_apps_dev_tools);
929 const bool load_unpacked_disabled =
930 ExtensionManagementFactory::GetForBrowserContext(profile)
931 ->BlacklistedByDefault();
932 results.SetBoolean("loadUnpackedDisabled", load_unpacked_disabled);
934 web_ui()->CallJavascriptFunction(
935 "extensions.ExtensionSettings.returnExtensionsData", results);
937 MaybeRegisterForNotifications();
938 UMA_HISTOGRAM_BOOLEAN("ExtensionSettings.ShouldDoVerificationCheck",
939 should_do_verification_check_);
940 if (should_do_verification_check_) {
941 should_do_verification_check_ = false;
942 ExtensionSystem::Get(Profile::FromWebUI(web_ui()))
943 ->install_verifier()
944 ->VerifyAllExtensions();
948 void ExtensionSettingsHandler::HandleToggleDeveloperMode(
949 const base::ListValue* args) {
950 Profile* profile = Profile::FromWebUI(web_ui());
951 if (profile->IsSupervised())
952 return;
954 bool developer_mode =
955 !profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
956 profile->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode,
957 developer_mode);
960 void ExtensionSettingsHandler::HandleInspectMessage(
961 const base::ListValue* args) {
962 std::string extension_id;
963 std::string render_process_id_str;
964 std::string render_view_id_str;
965 int render_process_id;
966 int render_view_id;
967 bool incognito;
968 CHECK_EQ(4U, args->GetSize());
969 CHECK(args->GetString(0, &extension_id));
970 CHECK(args->GetString(1, &render_process_id_str));
971 CHECK(args->GetString(2, &render_view_id_str));
972 CHECK(args->GetBoolean(3, &incognito));
973 CHECK(base::StringToInt(render_process_id_str, &render_process_id));
974 CHECK(base::StringToInt(render_view_id_str, &render_view_id));
976 if (render_process_id == -1) {
977 // This message is for a lazy background page. Start the page if necessary.
978 const Extension* extension =
979 extension_service_->extensions()->GetByID(extension_id);
980 DCHECK(extension);
981 Profile* profile = Profile::FromWebUI(web_ui());
982 if (incognito)
983 profile = profile->GetOffTheRecordProfile();
984 devtools_util::InspectBackgroundPage(extension, profile);
985 return;
988 RenderViewHost* host = RenderViewHost::FromID(render_process_id,
989 render_view_id);
990 if (!host || !WebContents::FromRenderViewHost(host)) {
991 // This can happen if the host has gone away since the page was displayed.
992 return;
995 DevToolsWindow::OpenDevToolsWindow(WebContents::FromRenderViewHost(host));
998 void ExtensionSettingsHandler::HandleLaunchMessage(
999 const base::ListValue* args) {
1000 CHECK_EQ(1U, args->GetSize());
1001 std::string extension_id;
1002 CHECK(args->GetString(0, &extension_id));
1003 const Extension* extension =
1004 extension_service_->GetExtensionById(extension_id, false);
1005 OpenApplication(AppLaunchParams(extension_service_->profile(), extension,
1006 extensions::LAUNCH_CONTAINER_WINDOW,
1007 NEW_WINDOW));
1010 void ExtensionSettingsHandler::HandleReloadMessage(
1011 const base::ListValue* args) {
1012 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1013 CHECK(!extension_id.empty());
1014 extension_service_->ReloadExtensionWithQuietFailure(extension_id);
1017 void ExtensionSettingsHandler::HandleRepairMessage(
1018 const base::ListValue* args) {
1019 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1020 CHECK(!extension_id.empty());
1021 scoped_refptr<WebstoreReinstaller> reinstaller(new WebstoreReinstaller(
1022 web_contents(),
1023 extension_id,
1024 base::Bind(&ExtensionSettingsHandler::OnReinstallComplete,
1025 AsWeakPtr())));
1026 reinstaller->BeginReinstall();
1029 void ExtensionSettingsHandler::HandleEnableMessage(
1030 const base::ListValue* args) {
1031 CHECK_EQ(2U, args->GetSize());
1032 std::string extension_id, enable_str;
1033 CHECK(args->GetString(0, &extension_id));
1034 CHECK(args->GetString(1, &enable_str));
1036 const Extension* extension =
1037 extension_service_->GetInstalledExtension(extension_id);
1038 if (!extension)
1039 return;
1041 if (!management_policy_->UserMayModifySettings(extension, NULL)) {
1042 LOG(ERROR) << "An attempt was made to enable an extension that is "
1043 << "non-usermanagable. Extension id: " << extension->id();
1044 return;
1047 if (enable_str == "true") {
1048 ExtensionPrefs* prefs = ExtensionPrefs::Get(extension_service_->profile());
1049 if (prefs->DidExtensionEscalatePermissions(extension_id)) {
1050 ShowExtensionDisabledDialog(
1051 extension_service_, web_ui()->GetWebContents(), extension);
1052 } else if ((prefs->GetDisableReasons(extension_id) &
1053 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) &&
1054 !requirements_checker_.get()) {
1055 // Recheck the requirements.
1056 scoped_refptr<const Extension> extension =
1057 extension_service_->GetExtensionById(extension_id,
1058 true /* include disabled */);
1059 requirements_checker_.reset(new RequirementsChecker);
1060 requirements_checker_->Check(
1061 extension,
1062 base::Bind(&ExtensionSettingsHandler::OnRequirementsChecked,
1063 AsWeakPtr(), extension_id));
1064 } else {
1065 extension_service_->EnableExtension(extension_id);
1067 } else {
1068 extension_service_->DisableExtension(
1069 extension_id, Extension::DISABLE_USER_ACTION);
1073 void ExtensionSettingsHandler::HandleEnableIncognitoMessage(
1074 const base::ListValue* args) {
1075 CHECK_EQ(2U, args->GetSize());
1076 std::string extension_id, enable_str;
1077 CHECK(args->GetString(0, &extension_id));
1078 CHECK(args->GetString(1, &enable_str));
1079 const Extension* extension =
1080 extension_service_->GetInstalledExtension(extension_id);
1081 if (!extension)
1082 return;
1084 // Flipping the incognito bit will generate unload/load notifications for the
1085 // extension, but we don't want to reload the page, because a) we've already
1086 // updated the UI to reflect the change, and b) we want the yellow warning
1087 // text to stay until the user has left the page.
1089 // TODO(aa): This creates crappiness in some cases. For example, in a main
1090 // window, when toggling this, the browser action will flicker because it gets
1091 // unloaded, then reloaded. It would be better to have a dedicated
1092 // notification for this case.
1094 // Bug: http://crbug.com/41384
1095 base::AutoReset<bool> auto_reset_ignore_notifications(
1096 &ignore_notifications_, true);
1097 util::SetIsIncognitoEnabled(extension->id(),
1098 extension_service_->profile(),
1099 enable_str == "true");
1102 void ExtensionSettingsHandler::HandleEnableErrorCollectionMessage(
1103 const base::ListValue* args) {
1104 CHECK_EQ(2u, args->GetSize());
1105 std::string extension_id;
1106 std::string enable_str;
1107 CHECK(args->GetString(0, &extension_id));
1108 CHECK(args->GetString(1, &enable_str));
1109 bool enabled = enable_str == "true";
1110 ErrorConsole::Get(Profile::FromWebUI(web_ui()))
1111 ->SetReportingAllForExtension(extension_id, enabled);
1114 void ExtensionSettingsHandler::HandleAllowFileAccessMessage(
1115 const base::ListValue* args) {
1116 CHECK_EQ(2U, args->GetSize());
1117 std::string extension_id, allow_str;
1118 CHECK(args->GetString(0, &extension_id));
1119 CHECK(args->GetString(1, &allow_str));
1120 const Extension* extension =
1121 extension_service_->GetInstalledExtension(extension_id);
1122 if (!extension)
1123 return;
1125 if (!management_policy_->UserMayModifySettings(extension, NULL)) {
1126 LOG(ERROR) << "An attempt was made to change allow file access of an"
1127 << " extension that is non-usermanagable. Extension id : "
1128 << extension->id();
1129 return;
1132 util::SetAllowFileAccess(
1133 extension_id, extension_service_->profile(), allow_str == "true");
1136 void ExtensionSettingsHandler::HandleAllowOnAllUrlsMessage(
1137 const base::ListValue* args) {
1138 DCHECK(FeatureSwitch::scripts_require_action()->IsEnabled());
1139 CHECK_EQ(2u, args->GetSize());
1140 std::string extension_id;
1141 std::string allow_str;
1142 CHECK(args->GetString(0, &extension_id));
1143 CHECK(args->GetString(1, &allow_str));
1144 util::SetAllowedScriptingOnAllUrls(extension_id,
1145 extension_service_->GetBrowserContext(),
1146 allow_str == "true");
1149 void ExtensionSettingsHandler::HandleUninstallMessage(
1150 const base::ListValue* args) {
1151 CHECK_EQ(1U, args->GetSize());
1152 std::string extension_id;
1153 CHECK(args->GetString(0, &extension_id));
1154 const Extension* extension =
1155 extension_service_->GetInstalledExtension(extension_id);
1156 if (!extension)
1157 return;
1159 if (!management_policy_->UserMayModifySettings(extension, NULL) ||
1160 management_policy_->MustRemainInstalled(extension, NULL)) {
1161 LOG(ERROR) << "An attempt was made to uninstall an extension that is "
1162 << "non-usermanagable. Extension id : " << extension->id();
1163 return;
1166 if (!extension_id_prompting_.empty())
1167 return; // Only one prompt at a time.
1169 extension_id_prompting_ = extension_id;
1171 GetExtensionUninstallDialog()->ConfirmUninstall(extension);
1174 void ExtensionSettingsHandler::HandleOptionsMessage(
1175 const base::ListValue* args) {
1176 const Extension* extension = GetActiveExtension(args);
1177 if (!extension || OptionsPageInfo::GetOptionsPage(extension).is_empty())
1178 return;
1179 ExtensionTabUtil::OpenOptionsPage(extension,
1180 chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()));
1183 void ExtensionSettingsHandler::HandlePermissionsMessage(
1184 const base::ListValue* args) {
1185 std::string extension_id(base::UTF16ToUTF8(ExtractStringValue(args)));
1186 CHECK(!extension_id.empty());
1187 const Extension* extension =
1188 ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))
1189 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
1190 if (!extension)
1191 return;
1193 if (!extension_id_prompting_.empty())
1194 return; // Only one prompt at a time.
1196 extension_id_prompting_ = extension->id();
1198 // Show the new-style extensions dialog when the flag is set. The flag cannot
1199 // be set on Mac platforms.
1200 if (CommandLine::ForCurrentProcess()->HasSwitch(
1201 switches::kEnableExtensionInfoDialog)) {
1202 UMA_HISTOGRAM_ENUMERATION("Apps.AppInfoDialog.Launches",
1203 AppInfoLaunchSource::FROM_EXTENSIONS_PAGE,
1204 AppInfoLaunchSource::NUM_LAUNCH_SOURCES);
1206 // Display the dialog at a size similar to the app list.
1207 const int kAppInfoDialogWidth = 380;
1208 const int kAppInfoDialogHeight = 490;
1209 ShowAppInfoInNativeDialog(
1210 web_contents()->GetTopLevelNativeWindow(),
1211 gfx::Size(kAppInfoDialogWidth, kAppInfoDialogHeight),
1212 Profile::FromWebUI(web_ui()),
1213 extension,
1214 base::Bind(&ExtensionSettingsHandler::AppInfoDialogClosed,
1215 base::Unretained(this)));
1216 } else {
1217 prompt_.reset(new ExtensionInstallPrompt(web_contents()));
1218 std::vector<base::FilePath> retained_file_paths;
1219 if (extension->permissions_data()->HasAPIPermission(
1220 APIPermission::kFileSystem)) {
1221 std::vector<apps::SavedFileEntry> retained_file_entries =
1222 apps::SavedFilesService::Get(Profile::FromWebUI(web_ui()))
1223 ->GetAllFileEntries(extension_id_prompting_);
1224 for (size_t i = 0; i < retained_file_entries.size(); ++i) {
1225 retained_file_paths.push_back(retained_file_entries[i].path);
1228 std::vector<base::string16> retained_device_messages;
1229 if (extension->permissions_data()->HasAPIPermission(APIPermission::kUsb)) {
1230 retained_device_messages =
1231 extensions::DevicePermissionsManager::Get(
1232 Profile::FromWebUI(web_ui()))
1233 ->GetPermissionMessageStrings(extension_id_prompting_);
1236 // The BrokerDelegate manages its own lifetime.
1237 prompt_->ReviewPermissions(new BrokerDelegate(AsWeakPtr()),
1238 extension,
1239 retained_file_paths,
1240 retained_device_messages);
1244 void ExtensionSettingsHandler::HandleShowButtonMessage(
1245 const base::ListValue* args) {
1246 const Extension* extension = GetActiveExtension(args);
1247 if (!extension)
1248 return;
1249 ExtensionActionAPI::SetBrowserActionVisibility(
1250 ExtensionPrefs::Get(extension_service_->profile()),
1251 extension->id(),
1252 true);
1255 void ExtensionSettingsHandler::HandleAutoUpdateMessage(
1256 const base::ListValue* args) {
1257 ExtensionUpdater* updater = extension_service_->updater();
1258 if (updater) {
1259 ExtensionUpdater::CheckParams params;
1260 params.install_immediately = true;
1261 updater->CheckNow(params);
1265 void ExtensionSettingsHandler::HandleDismissADTPromoMessage(
1266 const base::ListValue* args) {
1267 DCHECK(args->empty());
1268 Profile::FromWebUI(web_ui())->GetPrefs()->SetBoolean(
1269 prefs::kExtensionsUIDismissedADTPromo, true);
1272 void ExtensionSettingsHandler::HandleShowPath(const base::ListValue* args) {
1273 DCHECK(!args->empty());
1274 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1276 Profile* profile = Profile::FromWebUI(web_ui());
1277 ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
1278 const Extension* extension = registry->GetExtensionById(
1279 extension_id,
1280 ExtensionRegistry::EVERYTHING);
1281 CHECK(extension);
1282 // We explicitly show manifest.json in order to work around an issue in OSX
1283 // where opening the directory doesn't focus the Finder.
1284 platform_util::ShowItemInFolder(profile,
1285 extension->path().Append(kManifestFilename));
1288 void ExtensionSettingsHandler::ShowAlert(const std::string& message) {
1289 base::ListValue arguments;
1290 arguments.Append(new base::StringValue(message));
1291 web_ui()->CallJavascriptFunction("alert", arguments);
1294 const Extension* ExtensionSettingsHandler::GetActiveExtension(
1295 const base::ListValue* args) {
1296 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args));
1297 CHECK(!extension_id.empty());
1298 return extension_service_->GetExtensionById(extension_id, false);
1301 void ExtensionSettingsHandler::MaybeUpdateAfterNotification() {
1302 WebContents* contents = web_ui()->GetWebContents();
1303 if (!ignore_notifications_ && contents && contents->GetRenderViewHost())
1304 HandleRequestExtensionsData(NULL);
1305 deleting_rvh_ = NULL;
1308 void ExtensionSettingsHandler::MaybeRegisterForNotifications() {
1309 if (registered_for_notifications_)
1310 return;
1312 registered_for_notifications_ = true;
1313 Profile* profile = Profile::FromWebUI(web_ui());
1315 // Register for notifications that we need to reload the page.
1316 registrar_.Add(this,
1317 extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
1318 content::Source<Profile>(profile));
1319 registrar_.Add(this,
1320 extensions::NOTIFICATION_EXTENSION_HOST_CREATED,
1321 content::NotificationService::AllBrowserContextsAndSources());
1322 registrar_.Add(this,
1323 chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
1324 content::NotificationService::AllBrowserContextsAndSources());
1325 registrar_.Add(this,
1326 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
1327 content::NotificationService::AllBrowserContextsAndSources());
1328 registrar_.Add(
1329 this,
1330 extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
1331 content::Source<ExtensionPrefs>(ExtensionPrefs::Get(profile)));
1332 registrar_.Add(this,
1333 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
1334 content::NotificationService::AllBrowserContextsAndSources());
1335 registrar_.Add(this,
1336 content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
1337 content::NotificationService::AllBrowserContextsAndSources());
1339 extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
1341 content::WebContentsObserver::Observe(web_ui()->GetWebContents());
1343 warning_service_observer_.Add(
1344 ExtensionSystem::Get(profile)->warning_service());
1346 error_console_observer_.Add(ErrorConsole::Get(profile));
1348 extension_management_observer_.Add(
1349 ExtensionManagementFactory::GetForBrowserContext(profile));
1352 std::vector<ExtensionPage>
1353 ExtensionSettingsHandler::GetInspectablePagesForExtension(
1354 const Extension* extension, bool extension_is_enabled) {
1355 std::vector<ExtensionPage> result;
1357 // Get the extension process's active views.
1358 extensions::ProcessManager* process_manager =
1359 ExtensionSystem::Get(extension_service_->profile())->process_manager();
1360 GetInspectablePagesForExtensionProcess(
1361 extension,
1362 process_manager->GetRenderViewHostsForExtension(extension->id()),
1363 &result);
1365 // Get app window views
1366 GetAppWindowPagesForExtensionProfile(
1367 extension, extension_service_->profile(), &result);
1369 // Include a link to start the lazy background page, if applicable.
1370 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
1371 extension_is_enabled &&
1372 !process_manager->GetBackgroundHostForExtension(extension->id())) {
1373 result.push_back(ExtensionPage(
1374 BackgroundInfo::GetBackgroundURL(extension),
1377 false,
1378 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
1381 // Repeat for the incognito process, if applicable. Don't try to get
1382 // app windows for incognito processes.
1383 if (extension_service_->profile()->HasOffTheRecordProfile() &&
1384 IncognitoInfo::IsSplitMode(extension) &&
1385 util::IsIncognitoEnabled(extension->id(),
1386 extension_service_->profile())) {
1387 extensions::ProcessManager* process_manager =
1388 ExtensionSystem::Get(extension_service_->profile()->
1389 GetOffTheRecordProfile())->process_manager();
1390 GetInspectablePagesForExtensionProcess(
1391 extension,
1392 process_manager->GetRenderViewHostsForExtension(extension->id()),
1393 &result);
1395 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
1396 extension_is_enabled &&
1397 !process_manager->GetBackgroundHostForExtension(extension->id())) {
1398 result.push_back(ExtensionPage(
1399 BackgroundInfo::GetBackgroundURL(extension),
1402 true,
1403 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
1407 return result;
1410 void ExtensionSettingsHandler::GetInspectablePagesForExtensionProcess(
1411 const Extension* extension,
1412 const std::set<RenderViewHost*>& views,
1413 std::vector<ExtensionPage>* result) {
1414 bool has_generated_background_page =
1415 BackgroundInfo::HasGeneratedBackgroundPage(extension);
1416 for (std::set<RenderViewHost*>::const_iterator iter = views.begin();
1417 iter != views.end(); ++iter) {
1418 RenderViewHost* host = *iter;
1419 WebContents* web_contents = WebContents::FromRenderViewHost(host);
1420 ViewType host_type = GetViewType(web_contents);
1421 if (host == deleting_rvh_ ||
1422 VIEW_TYPE_EXTENSION_POPUP == host_type ||
1423 VIEW_TYPE_EXTENSION_DIALOG == host_type)
1424 continue;
1426 GURL url = web_contents->GetURL();
1427 content::RenderProcessHost* process = host->GetProcess();
1428 bool is_background_page =
1429 (url == BackgroundInfo::GetBackgroundURL(extension));
1430 result->push_back(
1431 ExtensionPage(url,
1432 process->GetID(),
1433 host->GetRoutingID(),
1434 process->GetBrowserContext()->IsOffTheRecord(),
1435 is_background_page && has_generated_background_page));
1439 void ExtensionSettingsHandler::GetAppWindowPagesForExtensionProfile(
1440 const Extension* extension,
1441 Profile* profile,
1442 std::vector<ExtensionPage>* result) {
1443 AppWindowRegistry* registry = AppWindowRegistry::Get(profile);
1444 if (!registry) return;
1446 const AppWindowRegistry::AppWindowList windows =
1447 registry->GetAppWindowsForApp(extension->id());
1449 bool has_generated_background_page =
1450 BackgroundInfo::HasGeneratedBackgroundPage(extension);
1451 for (AppWindowRegistry::const_iterator it = windows.begin();
1452 it != windows.end();
1453 ++it) {
1454 WebContents* web_contents = (*it)->web_contents();
1455 RenderViewHost* host = web_contents->GetRenderViewHost();
1456 content::RenderProcessHost* process = host->GetProcess();
1458 bool is_background_page =
1459 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
1460 result->push_back(
1461 ExtensionPage(web_contents->GetURL(),
1462 process->GetID(),
1463 host->GetRoutingID(),
1464 process->GetBrowserContext()->IsOffTheRecord(),
1465 is_background_page && has_generated_background_page));
1469 ExtensionUninstallDialog*
1470 ExtensionSettingsHandler::GetExtensionUninstallDialog() {
1471 #if !defined(OS_ANDROID)
1472 if (!extension_uninstall_dialog_.get()) {
1473 Browser* browser = chrome::FindBrowserWithWebContents(
1474 web_ui()->GetWebContents());
1475 extension_uninstall_dialog_.reset(
1476 ExtensionUninstallDialog::Create(extension_service_->profile(),
1477 browser->window()->GetNativeWindow(),
1478 this));
1480 return extension_uninstall_dialog_.get();
1481 #else
1482 return NULL;
1483 #endif // !defined(OS_ANDROID)
1486 void ExtensionSettingsHandler::OnReinstallComplete(
1487 bool success,
1488 const std::string& error,
1489 webstore_install::Result result) {
1490 MaybeUpdateAfterNotification();
1493 void ExtensionSettingsHandler::OnRequirementsChecked(
1494 std::string extension_id,
1495 std::vector<std::string> requirement_errors) {
1496 if (requirement_errors.empty()) {
1497 extension_service_->EnableExtension(extension_id);
1498 } else {
1499 ExtensionErrorReporter::GetInstance()->ReportError(
1500 base::UTF8ToUTF16(JoinString(requirement_errors, ' ')),
1501 true); // Be noisy.
1503 requirements_checker_.reset();
1506 } // namespace extensions