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
;
111 const char kAppsDeveloperToolsExtensionId
[] =
112 "ohmmkhmmmpcnpikjeljgnaoabkaalbgc";
115 namespace extensions
{
117 ExtensionPage::ExtensionPage(const GURL
& url
,
118 int render_process_id
,
121 bool generated_background_page
)
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
{
138 explicit BrokerDelegate(
139 const base::WeakPtr
<ExtensionSettingsHandler
>& delegate
)
140 : delegate_(delegate
) {}
142 // ExtensionInstallPrompt::Delegate implementation.
143 virtual void InstallUIProceed() override
{
145 delegate_
->InstallUIProceed();
149 virtual void InstallUIAbort(bool user_initiated
) override
{
151 delegate_
->InstallUIAbort(user_initiated
);
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),
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),
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) {
204 void ExtensionSettingsHandler::RegisterProfilePrefs(
205 user_prefs::PrefRegistrySyncable
* registry
) {
206 registry
->RegisterBooleanPref(
207 prefs::kExtensionsUIDeveloperMode
,
209 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF
);
210 registry
->RegisterBooleanPref(
211 prefs::kExtensionsUIDismissedADTPromo
,
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
=
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
);
254 ExtensionIconSource::GetIconURL(extension
,
255 extension_misc::EXTENSION_ICON_MEDIUM
,
256 ExtensionIconSet::MATCH_BIGGER
,
258 if (Manifest::IsUnpackedLocation(extension
->location())) {
259 extension_data
->SetString("path", extension
->path().value());
260 extension_data
->SetString(
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(
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(
297 for (ExtensionSet::const_iterator i
= dependent_extensions
->begin();
298 i
!= dependent_extensions
->end();
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(
320 util::AllowedScriptingOnAllUrls(
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
);
350 case BLACKLISTED_CWS_POLICY_VIOLATION
:
351 blacklist_text
= l10n_util::GetStringUTF16(
352 IDS_OPTIONS_BLACKLISTED_CWS_POLICY_VIOLATION
);
355 case BLACKLISTED_POTENTIALLY_UNWANTED
:
356 blacklist_text
= l10n_util::GetStringUTF16(
357 IDS_OPTIONS_BLACKLISTED_POTENTIALLY_UNWANTED
);
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);
369 extension_data
->SetInteger("order", 2);
371 if (!ExtensionActionAPI::GetBrowserActionVisibility(prefs
, extension
->id())) {
372 extension_data
->SetBoolean("enable_show_button", true);
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
) {
382 view_value
->SetString("path", iter
->url
.path().substr(1));
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(
399 extension_action_manager
->GetBrowserAction(*extension
) ||
400 extension_action_manager
->GetPageAction(*extension
));
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(
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();
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
);
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
));
483 "extensionSettingsSuggestGallery",
484 l10n_util::GetStringFUTF16(
485 IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY
,
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
));
493 "extensionSettingsGetMoreExtensionsUrl",
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
));
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",
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
));
584 "extensionSettingsAppsDevToolsPromoHTML",
585 l10n_util::GetStringFUTF16(
586 IDS_EXTENSIONS_APPS_DEV_TOOLS_PROMO_HTML
,
588 google_util::AppendGoogleLocaleParam(
589 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() +
590 kAppsDeveloperToolsExtensionId
),
591 g_browser_process
->GetApplicationLocale()).spec())));
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
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
))
619 MaybeUpdateAfterNotification();
622 void ExtensionSettingsHandler::DidStartNavigationToPendingEntry(
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
632 if (!extension_service_
) {
633 Profile
* profile
= Profile::FromWebUI(web_ui())->GetOriginalProfile();
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
,
645 web_ui()->RegisterMessageCallback("extensionSettingsToggleDeveloperMode",
646 base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode
,
648 web_ui()->RegisterMessageCallback("extensionSettingsInspect",
649 base::Bind(&ExtensionSettingsHandler::HandleInspectMessage
,
651 web_ui()->RegisterMessageCallback("extensionSettingsLaunch",
652 base::Bind(&ExtensionSettingsHandler::HandleLaunchMessage
,
654 web_ui()->RegisterMessageCallback("extensionSettingsReload",
655 base::Bind(&ExtensionSettingsHandler::HandleReloadMessage
,
657 web_ui()->RegisterMessageCallback("extensionSettingsRepair",
658 base::Bind(&ExtensionSettingsHandler::HandleRepairMessage
,
660 web_ui()->RegisterMessageCallback("extensionSettingsEnable",
661 base::Bind(&ExtensionSettingsHandler::HandleEnableMessage
,
663 web_ui()->RegisterMessageCallback("extensionSettingsEnableIncognito",
664 base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage
,
666 web_ui()->RegisterMessageCallback("extensionSettingsEnableErrorCollection",
667 base::Bind(&ExtensionSettingsHandler::HandleEnableErrorCollectionMessage
,
669 web_ui()->RegisterMessageCallback("extensionSettingsAllowFileAccess",
670 base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage
,
672 web_ui()->RegisterMessageCallback("extensionSettingsAllowOnAllUrls",
673 base::Bind(&ExtensionSettingsHandler::HandleAllowOnAllUrlsMessage
,
675 web_ui()->RegisterMessageCallback("extensionSettingsUninstall",
676 base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage
,
678 web_ui()->RegisterMessageCallback("extensionSettingsOptions",
679 base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage
,
681 web_ui()->RegisterMessageCallback("extensionSettingsPermissions",
682 base::Bind(&ExtensionSettingsHandler::HandlePermissionsMessage
,
684 web_ui()->RegisterMessageCallback("extensionSettingsShowButton",
685 base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage
,
687 web_ui()->RegisterMessageCallback("extensionSettingsAutoupdate",
688 base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage
,
690 web_ui()->RegisterMessageCallback("extensionSettingsDismissADTPromo",
691 base::Bind(&ExtensionSettingsHandler::HandleDismissADTPromoMessage
,
693 web_ui()->RegisterMessageCallback("extensionSettingsShowPath",
694 base::Bind(&ExtensionSettingsHandler::HandleShowPath
,
698 void ExtensionSettingsHandler::OnErrorAdded(const ExtensionError
* error
) {
699 MaybeUpdateAfterNotification();
702 void ExtensionSettingsHandler::Observe(
704 const content::NotificationSource
& source
,
705 const content::NotificationDetails
& details
) {
706 Profile
* profile
= Profile::FromWebUI(web_ui());
707 Profile
* source_profile
= NULL
;
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();
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
))
727 MaybeUpdateAfterNotification();
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();
737 case extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED
:
738 case extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED
:
739 MaybeUpdateAfterNotification();
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(
747 base::Bind(&ExtensionSettingsHandler::MaybeUpdateAfterNotification
,
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);
795 ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))->GetExtensionById(
796 extension_id_prompting_
, ExtensionRegistry::TERMINATED
);
797 was_terminated
= true;
802 extension_service_
->UninstallExtension(
803 extension_id_prompting_
,
804 extensions::UNINSTALL_REASON_USER_INITIATED
,
805 base::Bind(&base::DoNothing
),
807 extension_id_prompting_
= "";
809 // There will be no EXTENSION_UNLOADED notification for terminated
810 // extensions as they were already unloaded.
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
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(
880 GetInspectablePagesForExtension(extension
->get(), true),
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(
890 GetInspectablePagesForExtension(extension
->get(), false),
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(
901 empty_pages
, // Terminated process has no active pages.
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
=
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()))
944 ->VerifyAllExtensions();
948 void ExtensionSettingsHandler::HandleToggleDeveloperMode(
949 const base::ListValue
* args
) {
950 Profile
* profile
= Profile::FromWebUI(web_ui());
951 if (profile
->IsSupervised())
954 bool developer_mode
=
955 !profile
->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode
);
956 profile
->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode
,
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
;
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
);
981 Profile
* profile
= Profile::FromWebUI(web_ui());
983 profile
= profile
->GetOffTheRecordProfile();
984 devtools_util::InspectBackgroundPage(extension
, profile
);
988 RenderViewHost
* host
= RenderViewHost::FromID(render_process_id
,
990 if (!host
|| !WebContents::FromRenderViewHost(host
)) {
991 // This can happen if the host has gone away since the page was displayed.
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
,
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(
1024 base::Bind(&ExtensionSettingsHandler::OnReinstallComplete
,
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
);
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();
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(
1062 base::Bind(&ExtensionSettingsHandler::OnRequirementsChecked
,
1063 AsWeakPtr(), extension_id
));
1065 extension_service_
->EnableExtension(extension_id
);
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
);
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
);
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 : "
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
);
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();
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())
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
);
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()),
1214 base::Bind(&ExtensionSettingsHandler::AppInfoDialogClosed
,
1215 base::Unretained(this)));
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()),
1239 retained_file_paths
,
1240 retained_device_messages
);
1244 void ExtensionSettingsHandler::HandleShowButtonMessage(
1245 const base::ListValue
* args
) {
1246 const Extension
* extension
= GetActiveExtension(args
);
1249 ExtensionActionAPI::SetBrowserActionVisibility(
1250 ExtensionPrefs::Get(extension_service_
->profile()),
1255 void ExtensionSettingsHandler::HandleAutoUpdateMessage(
1256 const base::ListValue
* args
) {
1257 ExtensionUpdater
* updater
= extension_service_
->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(
1280 ExtensionRegistry::EVERYTHING
);
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_
)
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());
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(
1362 process_manager
->GetRenderViewHostsForExtension(extension
->id()),
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
),
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(
1392 process_manager
->GetRenderViewHostsForExtension(extension
->id()),
1395 if (BackgroundInfo::HasLazyBackgroundPage(extension
) &&
1396 extension_is_enabled
&&
1397 !process_manager
->GetBackgroundHostForExtension(extension
->id())) {
1398 result
.push_back(ExtensionPage(
1399 BackgroundInfo::GetBackgroundURL(extension
),
1403 BackgroundInfo::HasGeneratedBackgroundPage(extension
)));
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
)
1426 GURL url
= web_contents
->GetURL();
1427 content::RenderProcessHost
* process
= host
->GetProcess();
1428 bool is_background_page
=
1429 (url
== BackgroundInfo::GetBackgroundURL(extension
));
1433 host
->GetRoutingID(),
1434 process
->GetBrowserContext()->IsOffTheRecord(),
1435 is_background_page
&& has_generated_background_page
));
1439 void ExtensionSettingsHandler::GetAppWindowPagesForExtensionProfile(
1440 const Extension
* extension
,
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();
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
));
1461 ExtensionPage(web_contents
->GetURL(),
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(),
1480 return extension_uninstall_dialog_
.get();
1483 #endif // !defined(OS_ANDROID)
1486 void ExtensionSettingsHandler::OnReinstallComplete(
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
);
1499 ExtensionErrorReporter::GetInstance()->ReportError(
1500 base::UTF8ToUTF16(JoinString(requirement_errors
, ' ')),
1503 requirements_checker_
.reset();
1506 } // namespace extensions