Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / webui / extensions / extension_settings_handler.cc
blob3ef1ffc3b3e620dd4c8dc927a3e4b0f997d1f6e6
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,
100 int render_view_id,
101 bool incognito,
102 bool generated_background_page)
103 : url(url),
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 {
118 public:
119 explicit BrokerDelegate(
120 const base::WeakPtr<ExtensionSettingsHandler>& delegate)
121 : delegate_(delegate) {}
123 // ExtensionInstallPrompt::Delegate implementation.
124 virtual void InstallUIProceed() OVERRIDE {
125 if (delegate_)
126 delegate_->InstallUIProceed();
127 delete this;
130 virtual void InstallUIAbort(bool user_initiated) OVERRIDE {
131 if (delegate_)
132 delegate_->InstallUIAbort(user_initiated);
133 delete this;
136 private:
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),
152 deleting_rvh_(NULL),
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),
173 deleting_rvh_(NULL),
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) {
182 // static
183 void ExtensionSettingsHandler::RegisterProfilePrefs(
184 user_prefs::PrefRegistrySyncable* registry) {
185 registry->RegisterBooleanPref(
186 prefs::kExtensionsUIDeveloperMode,
187 false,
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);
215 GURL icon =
216 ExtensionIconSource::GetIconURL(extension,
217 extension_misc::EXTENSION_ICON_MEDIUM,
218 ExtensionIconSet::MATCH_BIGGER,
219 !enabled, NULL);
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(
228 "terminated",
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);
262 else
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);
270 // Add views
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) {
276 // No leading slash.
277 view_value->SetString("path", iter->url.path().substr(1));
278 } else {
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(
293 "hasPopupAction",
294 extension_action_manager->GetBrowserAction(*extension) ||
295 extension_action_manager->GetPageAction(*extension));
297 // Add warnings.
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
314 // redundant).
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();
330 bool can_inspect =
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);
353 list->Append(item);
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
459 // uber extensions.
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))
470 return;
471 MaybeUpdateAfterNotification();
474 void ExtensionSettingsHandler::DidStartNavigationToPendingEntry(
475 const GURL& url,
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
483 // for testing.
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,
495 AsWeakPtr()));
496 web_ui()->RegisterMessageCallback("extensionSettingsToggleDeveloperMode",
497 base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode,
498 AsWeakPtr()));
499 web_ui()->RegisterMessageCallback("extensionSettingsInspect",
500 base::Bind(&ExtensionSettingsHandler::HandleInspectMessage,
501 AsWeakPtr()));
502 web_ui()->RegisterMessageCallback("extensionSettingsLaunch",
503 base::Bind(&ExtensionSettingsHandler::HandleLaunchMessage,
504 AsWeakPtr()));
505 web_ui()->RegisterMessageCallback("extensionSettingsReload",
506 base::Bind(&ExtensionSettingsHandler::HandleReloadMessage,
507 AsWeakPtr()));
508 web_ui()->RegisterMessageCallback("extensionSettingsEnable",
509 base::Bind(&ExtensionSettingsHandler::HandleEnableMessage,
510 AsWeakPtr()));
511 web_ui()->RegisterMessageCallback("extensionSettingsEnableIncognito",
512 base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage,
513 AsWeakPtr()));
514 web_ui()->RegisterMessageCallback("extensionSettingsAllowFileAccess",
515 base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage,
516 AsWeakPtr()));
517 web_ui()->RegisterMessageCallback("extensionSettingsUninstall",
518 base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage,
519 AsWeakPtr()));
520 web_ui()->RegisterMessageCallback("extensionSettingsOptions",
521 base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage,
522 AsWeakPtr()));
523 web_ui()->RegisterMessageCallback("extensionSettingsPermissions",
524 base::Bind(&ExtensionSettingsHandler::HandlePermissionsMessage,
525 AsWeakPtr()));
526 web_ui()->RegisterMessageCallback("extensionSettingsShowButton",
527 base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage,
528 AsWeakPtr()));
529 web_ui()->RegisterMessageCallback("extensionSettingsAutoupdate",
530 base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage,
531 AsWeakPtr()));
532 web_ui()->RegisterMessageCallback("extensionSettingsLoadUnpackedExtension",
533 base::Bind(&ExtensionSettingsHandler::HandleLoadUnpackedExtensionMessage,
534 AsWeakPtr()));
537 void ExtensionSettingsHandler::FileSelected(const base::FilePath& path,
538 int index,
539 void* params) {
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) {
546 NOTREACHED();
549 void ExtensionSettingsHandler::FileSelectionCanceled(void* params) {
552 void ExtensionSettingsHandler::OnErrorAdded(const ExtensionError* error) {
553 MaybeUpdateAfterNotification();
556 void ExtensionSettingsHandler::Observe(
557 int type,
558 const content::NotificationSource& source,
559 const content::NotificationDetails& details) {
560 Profile* profile = Profile::FromWebUI(web_ui());
561 Profile* source_profile = NULL;
562 switch (type) {
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();
575 // Fall through.
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))
580 return;
581 MaybeUpdateAfterNotification();
582 break;
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();
589 break;
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();
597 break;
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(
603 FROM_HERE,
604 base::Bind(&ExtensionSettingsHandler::MaybeUpdateAfterNotification,
605 AsWeakPtr()));
606 break;
607 default:
608 NOTREACHED();
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);
621 if (!extension) {
622 extension = extension_service_->GetTerminatedExtension(
623 extension_id_prompting_);
624 was_terminated = true;
626 if (!extension)
627 return;
629 extension_service_->UninstallExtension(extension_id_prompting_,
630 false, // External uninstall.
631 NULL); // Error.
632 extension_id_prompting_ = "";
634 // There will be no EXTENSION_UNLOADED notification for terminated
635 // extensions as they were already unloaded.
636 if (was_terminated)
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(
698 extension->get(),
699 GetInspectablePagesForExtension(extension->get(), true),
700 warnings));
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(
708 extension->get(),
709 GetInspectablePagesForExtension(extension->get(), false),
710 warnings));
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(
719 extension->get(),
720 empty_pages, // Terminated process has no active pages.
721 warnings));
724 results.Set("extensions", extensions_list);
726 bool is_managed = profile->IsManaged();
727 bool developer_mode =
728 !is_managed &&
729 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
730 results.SetBoolean("profileIsManaged", is_managed);
731 results.SetBoolean("developerMode", developer_mode);
732 results.SetBoolean(
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())
754 return;
756 bool developer_mode =
757 !profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
758 profile->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode,
759 developer_mode);
761 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsDevtool))
762 return;
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,
768 apps_debugger_path);
769 } else {
770 std::string extension_id =
771 profile->GetExtensionService()->component_loader()->GetExtensionID(
772 IDR_APPS_DEBUGGER_MANIFEST,
773 apps_debugger_path);
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;
786 int render_view_id;
787 bool incognito;
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);
800 DCHECK(extension);
801 Profile* profile = Profile::FromWebUI(web_ui());
802 if (incognito)
803 profile = profile->GetOffTheRecordProfile();
804 devtools_util::InspectBackgroundPage(extension, profile);
805 return;
808 RenderViewHost* host = RenderViewHost::FromID(render_process_id,
809 render_view_id);
810 if (!host) {
811 // This can happen if the host has gone away since the page was displayed.
812 return;
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,
827 NEW_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);
846 if (!extension ||
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();
850 return;
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(
867 extension,
868 base::Bind(&ExtensionSettingsHandler::OnRequirementsChecked,
869 AsWeakPtr(), extension_id));
870 } else {
871 extension_service_->EnableExtension(extension_id);
873 } else {
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);
887 if (!extension)
888 return;
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(),
904 extension_service_,
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);
916 if (!extension)
917 return;
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 : "
922 << extension->id();
923 return;
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);
937 if (!extension)
938 return;
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();
943 return;
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())
958 return;
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);
969 if (!extension)
970 extension = extension_service_->GetTerminatedExtension(extension_id);
971 if (!extension)
972 return;
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);
996 if (!extension)
997 return;
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();
1005 if (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(
1025 kSelectType,
1026 select_title,
1027 last_unpacked_directory_,
1028 NULL,
1029 kFileTypeIndex,
1030 base::FilePath::StringType(),
1031 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
1032 NULL);
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_)
1059 return;
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());
1081 registrar_.Add(
1082 this,
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,
1103 AsWeakPtr());
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(
1118 extension,
1119 process_manager->GetRenderViewHostsForExtension(extension->id()),
1120 &result);
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),
1134 false,
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(
1147 extension,
1148 process_manager->GetRenderViewHostsForExtension(extension->id()),
1149 &result);
1151 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
1152 extension_is_enabled &&
1153 !process_manager->GetBackgroundHostForExtension(extension->id())) {
1154 result.push_back(ExtensionPage(
1155 BackgroundInfo::GetBackgroundURL(extension),
1158 true,
1159 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
1163 return result;
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)
1180 continue;
1182 GURL url = web_contents->GetURL();
1183 content::RenderProcessHost* process = host->GetProcess();
1184 bool is_background_page =
1185 (url == BackgroundInfo::GetBackgroundURL(extension));
1186 result->push_back(
1187 ExtensionPage(url,
1188 process->GetID(),
1189 host->GetRoutingID(),
1190 process->GetBrowserContext()->IsOffTheRecord(),
1191 is_background_page && has_generated_background_page));
1195 void ExtensionSettingsHandler::GetShellWindowPagesForExtensionProfile(
1196 const Extension* extension,
1197 Profile* profile,
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));
1215 result->push_back(
1216 ExtensionPage(web_contents->GetURL(),
1217 process->GetID(),
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(),
1232 browser, this));
1234 return extension_uninstall_dialog_.get();
1235 #else
1236 return NULL;
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);
1245 } else {
1246 ExtensionErrorReporter::GetInstance()->ReportError(
1247 base::UTF8ToUTF16(JoinString(requirement_errors, ' ')),
1248 true /* be noisy */);
1250 requirements_checker_.reset();
1253 } // namespace extensions