Home | History | Annotate | Download | only in profile_resetter
      1 // Copyright (c) 2013 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/profile_resetter/resettable_settings_snapshot.h"
      6 
      7 #include "base/json/json_writer.h"
      8 #include "base/prefs/pref_service.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "base/values.h"
     11 #include "chrome/browser/browser_process.h"
     12 #include "chrome/browser/extensions/extension_service.h"
     13 #include "chrome/browser/feedback/feedback_data.h"
     14 #include "chrome/browser/feedback/feedback_util.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/search_engines/template_url_service.h"
     17 #include "chrome/browser/search_engines/template_url_service_factory.h"
     18 #include "chrome/common/chrome_version_info.h"
     19 #include "chrome/common/pref_names.h"
     20 #include "grit/generated_resources.h"
     21 #include "grit/google_chrome_strings.h"
     22 #include "ui/base/l10n/l10n_util.h"
     23 
     24 namespace {
     25 
     26 // Feedback bucket labels.
     27 const char kProfileResetPromptBucket[] = "SamplingOfSettingsResetPrompt";
     28 const char kProfileResetWebUIBucket[] = "ProfileResetReport";
     29 
     30 // Dictionary keys for feedback report.
     31 const char kDefaultSearchEnginePath[] = "default_search_engine";
     32 const char kEnabledExtensions[] = "enabled_extensions";
     33 const char kHomepageIsNewTabPage[] = "homepage_is_ntp";
     34 const char kHomepagePath[] = "homepage";
     35 const char kStartupTypePath[] = "startup_type";
     36 const char kStartupURLPath[] = "startup_urls";
     37 
     38 template <class StringType>
     39 void AddPair(ListValue* list,
     40              const base::string16& key,
     41              const StringType& value) {
     42   DictionaryValue* results = new DictionaryValue();
     43   results->SetString("key", key);
     44   results->SetString("value", value);
     45   list->Append(results);
     46 }
     47 
     48 }  // namespace
     49 
     50 ResettableSettingsSnapshot::ResettableSettingsSnapshot(Profile* profile)
     51     : startup_(SessionStartupPref::GetStartupPref(profile)) {
     52   // URLs are always stored sorted.
     53   std::sort(startup_.urls.begin(), startup_.urls.end());
     54 
     55   PrefService* prefs = profile->GetPrefs();
     56   DCHECK(prefs);
     57   homepage_ = prefs->GetString(prefs::kHomePage);
     58   homepage_is_ntp_ = prefs->GetBoolean(prefs::kHomePageIsNewTabPage);
     59 
     60   TemplateURLService* service =
     61       TemplateURLServiceFactory::GetForProfile(profile);
     62   DCHECK(service);
     63   TemplateURL* dse = service->GetDefaultSearchProvider();
     64   if (dse)
     65     dse_url_ = dse->url();
     66 
     67   ExtensionService* extension_service = profile->GetExtensionService();
     68   DCHECK(extension_service);
     69   const ExtensionSet* enabled_ext = extension_service->extensions();
     70   enabled_extensions_.reserve(enabled_ext->size());
     71 
     72   for (ExtensionSet::const_iterator it = enabled_ext->begin();
     73        it != enabled_ext->end(); ++it)
     74     enabled_extensions_.push_back(std::make_pair((*it)->id(), (*it)->name()));
     75 
     76   // ExtensionSet is sorted but it seems to be an implementation detail.
     77   std::sort(enabled_extensions_.begin(), enabled_extensions_.end());
     78 }
     79 
     80 ResettableSettingsSnapshot::~ResettableSettingsSnapshot() {}
     81 
     82 void ResettableSettingsSnapshot::Subtract(
     83     const ResettableSettingsSnapshot& snapshot) {
     84   ExtensionList extensions = base::STLSetDifference<ExtensionList>(
     85       enabled_extensions_, snapshot.enabled_extensions_);
     86   enabled_extensions_.swap(extensions);
     87 }
     88 
     89 int ResettableSettingsSnapshot::FindDifferentFields(
     90     const ResettableSettingsSnapshot& snapshot) const {
     91   int bit_mask = 0;
     92 
     93   if (startup_.type != snapshot.startup_.type ||
     94       startup_.urls != snapshot.startup_.urls)
     95     bit_mask |= STARTUP_MODE;
     96 
     97   if (homepage_is_ntp_ != snapshot.homepage_is_ntp_ ||
     98       homepage_ != snapshot.homepage_)
     99     bit_mask |= HOMEPAGE;
    100 
    101   if (dse_url_ != snapshot.dse_url_)
    102     bit_mask |= DSE_URL;
    103 
    104   if (enabled_extensions_ != snapshot.enabled_extensions_)
    105     bit_mask |= EXTENSIONS;
    106 
    107   COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS == 15,
    108                  add_new_field_here);
    109 
    110   return bit_mask;
    111 }
    112 
    113 std::string SerializeSettingsReport(const ResettableSettingsSnapshot& snapshot,
    114                                     int field_mask) {
    115   DictionaryValue dict;
    116 
    117   if (field_mask & ResettableSettingsSnapshot::STARTUP_MODE) {
    118     ListValue* list = new ListValue;
    119     const std::vector<GURL>& urls = snapshot.startup_urls();
    120     for (std::vector<GURL>::const_iterator i = urls.begin();
    121          i != urls.end(); ++i)
    122       list->AppendString(i->spec());
    123     dict.Set(kStartupURLPath, list);
    124     dict.SetInteger(kStartupTypePath, snapshot.startup_type());
    125   }
    126 
    127   if (field_mask & ResettableSettingsSnapshot::HOMEPAGE) {
    128     dict.SetString(kHomepagePath, snapshot.homepage());
    129     dict.SetBoolean(kHomepageIsNewTabPage, snapshot.homepage_is_ntp());
    130   }
    131 
    132   if (field_mask & ResettableSettingsSnapshot::DSE_URL)
    133     dict.SetString(kDefaultSearchEnginePath, snapshot.dse_url());
    134 
    135   if (field_mask & ResettableSettingsSnapshot::EXTENSIONS) {
    136     ListValue* list = new ListValue;
    137     const ResettableSettingsSnapshot::ExtensionList& extensions =
    138         snapshot.enabled_extensions();
    139     for (ResettableSettingsSnapshot::ExtensionList::const_iterator i =
    140          extensions.begin(); i != extensions.end(); ++i) {
    141       // Replace "\"" to simplify server-side analysis.
    142       std::string ext_name;
    143       base::ReplaceChars(i->second, "\"", "\'", &ext_name);
    144       list->AppendString(i->first + ";" + ext_name);
    145     }
    146     dict.Set(kEnabledExtensions, list);
    147   }
    148 
    149   COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS == 15,
    150                  serialize_new_field_here);
    151 
    152   std::string json;
    153   base::JSONWriter::Write(&dict, &json);
    154   return json;
    155 }
    156 
    157 void SendSettingsFeedback(const std::string& report,
    158                           Profile* profile,
    159                           SnapshotCaller caller) {
    160   scoped_refptr<FeedbackData> feedback_data = new FeedbackData();
    161   std::string bucket;
    162   switch (caller) {
    163     case PROFILE_RESET_WEBUI:
    164       bucket = kProfileResetWebUIBucket;
    165       break;
    166     case PROFILE_RESET_PROMPT:
    167       bucket = kProfileResetPromptBucket;
    168       break;
    169   }
    170   feedback_data->set_category_tag(bucket);
    171   feedback_data->set_description(report);
    172 
    173   feedback_data->set_image(scoped_ptr<std::string>(new std::string));
    174   feedback_data->set_profile(profile);
    175 
    176   feedback_data->set_page_url("");
    177   feedback_data->set_user_email("");
    178 
    179   feedback_util::SendReport(feedback_data);
    180 }
    181 
    182 ListValue* GetReadableFeedback(Profile* profile) {
    183   DCHECK(profile);
    184   ListValue* list = new ListValue;
    185   AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_LOCALE),
    186           g_browser_process->GetApplicationLocale());
    187   AddPair(list,
    188           l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_USER_AGENT),
    189           content::GetUserAgent(GURL()));
    190   chrome::VersionInfo version_info;
    191   std::string version = version_info.Version();
    192   version += chrome::VersionInfo::GetVersionStringModifier();
    193   AddPair(list,
    194           l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
    195           version);
    196 
    197   // Add snapshot data.
    198   ResettableSettingsSnapshot snapshot(profile);
    199   const std::vector<GURL>& urls = snapshot.startup_urls();
    200   std::string startup_urls;
    201   for (std::vector<GURL>::const_iterator i = urls.begin();
    202        i != urls.end(); ++i) {
    203     (startup_urls += i->host()) += ' ';
    204   }
    205   if (!startup_urls.empty()) {
    206     startup_urls.erase(startup_urls.end() - 1);
    207     AddPair(list,
    208             l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_URLS),
    209             startup_urls);
    210   }
    211 
    212   base::string16 startup_type;
    213   switch (snapshot.startup_type()) {
    214     case SessionStartupPref::DEFAULT:
    215       startup_type = l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_NEWTAB);
    216       break;
    217     case SessionStartupPref::LAST:
    218       startup_type = l10n_util::GetStringUTF16(
    219           IDS_OPTIONS_STARTUP_RESTORE_LAST_SESSION);
    220       break;
    221     case SessionStartupPref::URLS:
    222       startup_type = l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_PAGES);
    223       break;
    224     default:
    225       break;
    226   }
    227   AddPair(list,
    228           l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_TYPE),
    229           startup_type);
    230 
    231   if (!snapshot.homepage().empty()) {
    232     AddPair(list,
    233             l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE),
    234             snapshot.homepage());
    235   }
    236 
    237   int is_ntp_message_id = snapshot.homepage_is_ntp() ?
    238       IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_TRUE :
    239       IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_FALSE;
    240   AddPair(list,
    241           l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP),
    242           l10n_util::GetStringUTF16(is_ntp_message_id));
    243 
    244   TemplateURLService* service =
    245       TemplateURLServiceFactory::GetForProfile(profile);
    246   DCHECK(service);
    247   TemplateURL* dse = service->GetDefaultSearchProvider();
    248   if (dse) {
    249     AddPair(list,
    250             l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_DSE),
    251             TemplateURLService::GenerateSearchURL(dse).host());
    252   }
    253 
    254   const ResettableSettingsSnapshot::ExtensionList& extensions =
    255       snapshot.enabled_extensions();
    256   std::string extension_names;
    257   for (ResettableSettingsSnapshot::ExtensionList::const_iterator i =
    258        extensions.begin(); i != extensions.end(); ++i) {
    259     (extension_names += i->second) += '\n';
    260   }
    261   if (!extension_names.empty()) {
    262     extension_names.erase(extension_names.end() - 1);
    263     AddPair(list,
    264             l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_EXTENSIONS),
    265             extension_names);
    266   }
    267   return list;
    268 }
    269