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