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