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