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