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