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