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.
5 #include "chrome/browser/profile_resetter/resettable_settings_snapshot.h"
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 "extensions/common/extension_set.h"
21 #include "grit/generated_resources.h"
22 #include "grit/google_chrome_strings.h"
23 #include "ui/base/l10n/l10n_util.h"
27 // Feedback bucket labels.
28 const char kProfileResetPromptBucket
[] = "SamplingOfSettingsResetPrompt";
29 const char kProfileResetWebUIBucket
[] = "ProfileResetReport";
31 // Dictionary keys for feedback report.
32 const char kDefaultSearchEnginePath
[] = "default_search_engine";
33 const char kEnabledExtensions
[] = "enabled_extensions";
34 const char kHomepageIsNewTabPage
[] = "homepage_is_ntp";
35 const char kHomepagePath
[] = "homepage";
36 const char kStartupTypePath
[] = "startup_type";
37 const char kStartupURLPath
[] = "startup_urls";
39 template <class StringType
>
40 void AddPair(base::ListValue
* list
,
41 const base::string16
& key
,
42 const StringType
& value
) {
43 base::DictionaryValue
* results
= new base::DictionaryValue();
44 results
->SetString("key", key
);
45 results
->SetString("value", value
);
46 list
->Append(results
);
51 ResettableSettingsSnapshot::ResettableSettingsSnapshot(Profile
* profile
)
52 : startup_(SessionStartupPref::GetStartupPref(profile
)) {
53 // URLs are always stored sorted.
54 std::sort(startup_
.urls
.begin(), startup_
.urls
.end());
56 PrefService
* prefs
= profile
->GetPrefs();
58 homepage_
= prefs
->GetString(prefs::kHomePage
);
59 homepage_is_ntp_
= prefs
->GetBoolean(prefs::kHomePageIsNewTabPage
);
61 TemplateURLService
* service
=
62 TemplateURLServiceFactory::GetForProfile(profile
);
64 TemplateURL
* dse
= service
->GetDefaultSearchProvider();
66 dse_url_
= dse
->url();
68 ExtensionService
* extension_service
= profile
->GetExtensionService();
69 DCHECK(extension_service
);
70 const extensions::ExtensionSet
* enabled_ext
= extension_service
->extensions();
71 enabled_extensions_
.reserve(enabled_ext
->size());
73 for (extensions::ExtensionSet::const_iterator it
= enabled_ext
->begin();
74 it
!= enabled_ext
->end(); ++it
)
75 enabled_extensions_
.push_back(std::make_pair((*it
)->id(), (*it
)->name()));
77 // ExtensionSet is sorted but it seems to be an implementation detail.
78 std::sort(enabled_extensions_
.begin(), enabled_extensions_
.end());
81 ResettableSettingsSnapshot::~ResettableSettingsSnapshot() {}
83 void ResettableSettingsSnapshot::Subtract(
84 const ResettableSettingsSnapshot
& snapshot
) {
85 ExtensionList extensions
= base::STLSetDifference
<ExtensionList
>(
86 enabled_extensions_
, snapshot
.enabled_extensions_
);
87 enabled_extensions_
.swap(extensions
);
90 int ResettableSettingsSnapshot::FindDifferentFields(
91 const ResettableSettingsSnapshot
& snapshot
) const {
94 if (startup_
.type
!= snapshot
.startup_
.type
||
95 startup_
.urls
!= snapshot
.startup_
.urls
)
96 bit_mask
|= STARTUP_MODE
;
98 if (homepage_is_ntp_
!= snapshot
.homepage_is_ntp_
||
99 homepage_
!= snapshot
.homepage_
)
100 bit_mask
|= HOMEPAGE
;
102 if (dse_url_
!= snapshot
.dse_url_
)
105 if (enabled_extensions_
!= snapshot
.enabled_extensions_
)
106 bit_mask
|= EXTENSIONS
;
108 COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS
== 15,
114 std::string
SerializeSettingsReport(const ResettableSettingsSnapshot
& snapshot
,
116 base::DictionaryValue dict
;
118 if (field_mask
& ResettableSettingsSnapshot::STARTUP_MODE
) {
119 base::ListValue
* list
= new base::ListValue
;
120 const std::vector
<GURL
>& urls
= snapshot
.startup_urls();
121 for (std::vector
<GURL
>::const_iterator i
= urls
.begin();
122 i
!= urls
.end(); ++i
)
123 list
->AppendString(i
->spec());
124 dict
.Set(kStartupURLPath
, list
);
125 dict
.SetInteger(kStartupTypePath
, snapshot
.startup_type());
128 if (field_mask
& ResettableSettingsSnapshot::HOMEPAGE
) {
129 dict
.SetString(kHomepagePath
, snapshot
.homepage());
130 dict
.SetBoolean(kHomepageIsNewTabPage
, snapshot
.homepage_is_ntp());
133 if (field_mask
& ResettableSettingsSnapshot::DSE_URL
)
134 dict
.SetString(kDefaultSearchEnginePath
, snapshot
.dse_url());
136 if (field_mask
& ResettableSettingsSnapshot::EXTENSIONS
) {
137 base::ListValue
* list
= new base::ListValue
;
138 const ResettableSettingsSnapshot::ExtensionList
& extensions
=
139 snapshot
.enabled_extensions();
140 for (ResettableSettingsSnapshot::ExtensionList::const_iterator i
=
141 extensions
.begin(); i
!= extensions
.end(); ++i
) {
142 // Replace "\"" to simplify server-side analysis.
143 std::string ext_name
;
144 base::ReplaceChars(i
->second
, "\"", "\'", &ext_name
);
145 list
->AppendString(i
->first
+ ";" + ext_name
);
147 dict
.Set(kEnabledExtensions
, list
);
150 COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS
== 15,
151 serialize_new_field_here
);
154 base::JSONWriter::Write(&dict
, &json
);
158 void SendSettingsFeedback(const std::string
& report
,
160 SnapshotCaller caller
) {
161 scoped_refptr
<FeedbackData
> feedback_data
= new FeedbackData();
164 case PROFILE_RESET_WEBUI
:
165 bucket
= kProfileResetWebUIBucket
;
167 case PROFILE_RESET_PROMPT
:
168 bucket
= kProfileResetPromptBucket
;
171 feedback_data
->set_category_tag(bucket
);
172 feedback_data
->set_description(report
);
174 feedback_data
->set_image(scoped_ptr
<std::string
>(new std::string
));
175 feedback_data
->set_profile(profile
);
177 feedback_data
->set_page_url("");
178 feedback_data
->set_user_email("");
180 feedback_util::SendReport(feedback_data
);
183 base::ListValue
* GetReadableFeedback(Profile
* profile
) {
185 base::ListValue
* list
= new base::ListValue
;
186 AddPair(list
, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_LOCALE
),
187 g_browser_process
->GetApplicationLocale());
189 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_USER_AGENT
),
190 content::GetUserAgent(GURL()));
191 chrome::VersionInfo version_info
;
192 std::string version
= version_info
.Version();
193 version
+= chrome::VersionInfo::GetVersionStringModifier();
195 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME
),
198 // Add snapshot data.
199 ResettableSettingsSnapshot
snapshot(profile
);
200 const std::vector
<GURL
>& urls
= snapshot
.startup_urls();
201 std::string startup_urls
;
202 for (std::vector
<GURL
>::const_iterator i
= urls
.begin();
203 i
!= urls
.end(); ++i
) {
204 (startup_urls
+= i
->host()) += ' ';
206 if (!startup_urls
.empty()) {
207 startup_urls
.erase(startup_urls
.end() - 1);
209 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_URLS
),
213 base::string16 startup_type
;
214 switch (snapshot
.startup_type()) {
215 case SessionStartupPref::DEFAULT
:
216 startup_type
= l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_NEWTAB
);
218 case SessionStartupPref::LAST
:
219 startup_type
= l10n_util::GetStringUTF16(
220 IDS_OPTIONS_STARTUP_RESTORE_LAST_SESSION
);
222 case SessionStartupPref::URLS
:
223 startup_type
= l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_PAGES
);
229 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_TYPE
),
232 if (!snapshot
.homepage().empty()) {
234 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE
),
235 snapshot
.homepage());
238 int is_ntp_message_id
= snapshot
.homepage_is_ntp() ?
239 IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_TRUE
:
240 IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_FALSE
;
242 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP
),
243 l10n_util::GetStringUTF16(is_ntp_message_id
));
245 TemplateURLService
* service
=
246 TemplateURLServiceFactory::GetForProfile(profile
);
248 TemplateURL
* dse
= service
->GetDefaultSearchProvider();
251 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_DSE
),
252 TemplateURLService::GenerateSearchURL(dse
).host());
255 const ResettableSettingsSnapshot::ExtensionList
& extensions
=
256 snapshot
.enabled_extensions();
257 std::string extension_names
;
258 for (ResettableSettingsSnapshot::ExtensionList::const_iterator i
=
259 extensions
.begin(); i
!= extensions
.end(); ++i
) {
260 (extension_names
+= i
->second
) += '\n';
262 if (!extension_names
.empty()) {
263 extension_names
.erase(extension_names
.end() - 1);
265 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_EXTENSIONS
),