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/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/synchronization/cancellation_flag.h"
12 #include "base/values.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/search_engines/template_url_service_factory.h"
16 #include "chrome/common/channel_info.h"
17 #include "chrome/common/chrome_content_client.h"
18 #include "chrome/common/pref_names.h"
19 #include "chrome/grit/chromium_strings.h"
20 #include "chrome/grit/generated_resources.h"
21 #include "components/feedback/feedback_data.h"
22 #include "components/feedback/feedback_util.h"
23 #include "components/search_engines/template_url_service.h"
24 #include "components/version_info/version_info.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "extensions/browser/extension_registry.h"
27 #include "ui/base/l10n/l10n_util.h"
29 using feedback::FeedbackData
;
33 // Feedback bucket labels.
34 const char kProfileResetPromptBucket
[] = "SamplingOfSettingsResetPrompt";
35 const char kProfileResetWebUIBucket
[] = "ProfileResetReport";
37 // Dictionary keys for feedback report.
38 const char kDefaultSearchEnginePath
[] = "default_search_engine";
39 const char kEnabledExtensions
[] = "enabled_extensions";
40 const char kHomepageIsNewTabPage
[] = "homepage_is_ntp";
41 const char kHomepagePath
[] = "homepage";
42 const char kShortcuts
[] = "shortcuts";
43 const char kShowHomeButton
[] = "show_home_button";
44 const char kStartupTypePath
[] = "startup_type";
45 const char kStartupURLPath
[] = "startup_urls";
47 template <class StringType
>
48 void AddPair(base::ListValue
* list
,
49 const base::string16
& key
,
50 const StringType
& value
) {
51 base::DictionaryValue
* results
= new base::DictionaryValue();
52 results
->SetString("key", key
);
53 results
->SetString("value", value
);
54 list
->Append(results
);
59 ResettableSettingsSnapshot::ResettableSettingsSnapshot(
61 : startup_(SessionStartupPref::GetStartupPref(profile
)),
62 shortcuts_determined_(false),
63 weak_ptr_factory_(this) {
64 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
65 // URLs are always stored sorted.
66 std::sort(startup_
.urls
.begin(), startup_
.urls
.end());
68 PrefService
* prefs
= profile
->GetPrefs();
70 homepage_
= prefs
->GetString(prefs::kHomePage
);
71 homepage_is_ntp_
= prefs
->GetBoolean(prefs::kHomePageIsNewTabPage
);
72 show_home_button_
= prefs
->GetBoolean(prefs::kShowHomeButton
);
74 TemplateURLService
* service
=
75 TemplateURLServiceFactory::GetForProfile(profile
);
77 TemplateURL
* dse
= service
->GetDefaultSearchProvider();
79 dse_url_
= dse
->url();
81 const extensions::ExtensionSet
& enabled_ext
=
82 extensions::ExtensionRegistry::Get(profile
)->enabled_extensions();
83 enabled_extensions_
.reserve(enabled_ext
.size());
85 for (extensions::ExtensionSet::const_iterator it
= enabled_ext
.begin();
86 it
!= enabled_ext
.end(); ++it
)
87 enabled_extensions_
.push_back(std::make_pair((*it
)->id(), (*it
)->name()));
89 // ExtensionSet is sorted but it seems to be an implementation detail.
90 std::sort(enabled_extensions_
.begin(), enabled_extensions_
.end());
93 ResettableSettingsSnapshot::~ResettableSettingsSnapshot() {
94 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
95 if (cancellation_flag_
.get())
96 cancellation_flag_
->data
.Set();
99 void ResettableSettingsSnapshot::Subtract(
100 const ResettableSettingsSnapshot
& snapshot
) {
101 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
102 ExtensionList extensions
= base::STLSetDifference
<ExtensionList
>(
103 enabled_extensions_
, snapshot
.enabled_extensions_
);
104 enabled_extensions_
.swap(extensions
);
107 int ResettableSettingsSnapshot::FindDifferentFields(
108 const ResettableSettingsSnapshot
& snapshot
) const {
109 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
112 if (startup_
.type
!= snapshot
.startup_
.type
||
113 startup_
.urls
!= snapshot
.startup_
.urls
)
114 bit_mask
|= STARTUP_MODE
;
116 if (homepage_is_ntp_
!= snapshot
.homepage_is_ntp_
||
117 homepage_
!= snapshot
.homepage_
||
118 show_home_button_
!= snapshot
.show_home_button_
)
119 bit_mask
|= HOMEPAGE
;
121 if (dse_url_
!= snapshot
.dse_url_
)
124 if (enabled_extensions_
!= snapshot
.enabled_extensions_
)
125 bit_mask
|= EXTENSIONS
;
127 if (shortcuts_
!= snapshot
.shortcuts_
)
128 bit_mask
|= SHORTCUTS
;
130 static_assert(ResettableSettingsSnapshot::ALL_FIELDS
== 31,
131 "new field needs to be added here");
136 void ResettableSettingsSnapshot::RequestShortcuts(
137 const base::Closure
& callback
) {
138 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
139 DCHECK(!cancellation_flag_
.get() && !shortcuts_determined());
141 cancellation_flag_
= new SharedCancellationFlag
;
142 content::BrowserThread::PostTaskAndReplyWithResult(
143 content::BrowserThread::FILE,
145 base::Bind(&GetChromeLaunchShortcuts
, cancellation_flag_
),
146 base::Bind(&ResettableSettingsSnapshot::SetShortcutsAndReport
,
147 weak_ptr_factory_
.GetWeakPtr(),
151 void ResettableSettingsSnapshot::SetShortcutsAndReport(
152 const base::Closure
& callback
,
153 const std::vector
<ShortcutCommand
>& shortcuts
) {
154 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
155 shortcuts_
= shortcuts
;
156 shortcuts_determined_
= true;
157 cancellation_flag_
= NULL
;
159 if (!callback
.is_null())
163 std::string
SerializeSettingsReport(const ResettableSettingsSnapshot
& snapshot
,
165 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
166 base::DictionaryValue dict
;
168 if (field_mask
& ResettableSettingsSnapshot::STARTUP_MODE
) {
169 base::ListValue
* list
= new base::ListValue
;
170 const std::vector
<GURL
>& urls
= snapshot
.startup_urls();
171 for (std::vector
<GURL
>::const_iterator i
= urls
.begin();
172 i
!= urls
.end(); ++i
)
173 list
->AppendString(i
->spec());
174 dict
.Set(kStartupURLPath
, list
);
175 dict
.SetInteger(kStartupTypePath
, snapshot
.startup_type());
178 if (field_mask
& ResettableSettingsSnapshot::HOMEPAGE
) {
179 dict
.SetString(kHomepagePath
, snapshot
.homepage());
180 dict
.SetBoolean(kHomepageIsNewTabPage
, snapshot
.homepage_is_ntp());
181 dict
.SetBoolean(kShowHomeButton
, snapshot
.show_home_button());
184 if (field_mask
& ResettableSettingsSnapshot::DSE_URL
)
185 dict
.SetString(kDefaultSearchEnginePath
, snapshot
.dse_url());
187 if (field_mask
& ResettableSettingsSnapshot::EXTENSIONS
) {
188 base::ListValue
* list
= new base::ListValue
;
189 const ResettableSettingsSnapshot::ExtensionList
& extensions
=
190 snapshot
.enabled_extensions();
191 for (ResettableSettingsSnapshot::ExtensionList::const_iterator i
=
192 extensions
.begin(); i
!= extensions
.end(); ++i
) {
193 // Replace "\"" to simplify server-side analysis.
194 std::string ext_name
;
195 base::ReplaceChars(i
->second
, "\"", "\'", &ext_name
);
196 list
->AppendString(i
->first
+ ";" + ext_name
);
198 dict
.Set(kEnabledExtensions
, list
);
201 if (field_mask
& ResettableSettingsSnapshot::SHORTCUTS
) {
202 base::ListValue
* list
= new base::ListValue
;
203 const std::vector
<ShortcutCommand
>& shortcuts
= snapshot
.shortcuts();
204 for (std::vector
<ShortcutCommand
>::const_iterator i
= shortcuts
.begin();
205 i
!= shortcuts
.end(); ++i
) {
206 base::string16 arguments
;
207 // Replace "\"" to simplify server-side analysis.
208 base::ReplaceChars(i
->second
, base::ASCIIToUTF16("\""),
209 base::ASCIIToUTF16("\'"), &arguments
);
210 list
->AppendString(arguments
);
212 dict
.Set(kShortcuts
, list
);
215 static_assert(ResettableSettingsSnapshot::ALL_FIELDS
== 31,
216 "new field needs to be serialized here");
219 base::JSONWriter::Write(dict
, &json
);
223 void SendSettingsFeedback(const std::string
& report
,
225 SnapshotCaller caller
) {
226 scoped_refptr
<FeedbackData
> feedback_data
= new FeedbackData();
229 case PROFILE_RESET_WEBUI
:
230 bucket
= kProfileResetWebUIBucket
;
232 case PROFILE_RESET_PROMPT
:
233 bucket
= kProfileResetPromptBucket
;
236 feedback_data
->set_category_tag(bucket
);
237 feedback_data
->set_description(report
);
239 feedback_data
->set_image(make_scoped_ptr(new std::string
));
240 feedback_data
->set_context(profile
);
242 feedback_data
->set_page_url("");
243 feedback_data
->set_user_email("");
245 feedback_util::SendReport(feedback_data
);
248 scoped_ptr
<base::ListValue
> GetReadableFeedbackForSnapshot(
250 const ResettableSettingsSnapshot
& snapshot
) {
252 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
253 scoped_ptr
<base::ListValue
> list(new base::ListValue
);
255 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_LOCALE
),
256 g_browser_process
->GetApplicationLocale());
258 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_USER_AGENT
),
260 std::string version
= version_info::GetVersionNumber();
261 version
+= chrome::GetChannelString();
263 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME
),
266 // Add snapshot data.
267 const std::vector
<GURL
>& urls
= snapshot
.startup_urls();
268 std::string startup_urls
;
269 for (std::vector
<GURL
>::const_iterator i
= urls
.begin();
270 i
!= urls
.end(); ++i
) {
271 if (!startup_urls
.empty())
273 startup_urls
+= i
->host();
275 if (!startup_urls
.empty()) {
277 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_URLS
),
281 base::string16 startup_type
;
282 switch (snapshot
.startup_type()) {
283 case SessionStartupPref::DEFAULT
:
284 startup_type
= l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_NEWTAB
);
286 case SessionStartupPref::LAST
:
287 startup_type
= l10n_util::GetStringUTF16(
288 IDS_OPTIONS_STARTUP_RESTORE_LAST_SESSION
);
290 case SessionStartupPref::URLS
:
291 startup_type
= l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_PAGES
);
297 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_TYPE
),
300 if (!snapshot
.homepage().empty()) {
302 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE
),
303 snapshot
.homepage());
306 int is_ntp_message_id
= snapshot
.homepage_is_ntp() ?
307 IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_TRUE
:
308 IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_FALSE
;
310 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP
),
311 l10n_util::GetStringUTF16(is_ntp_message_id
));
313 int show_home_button_id
= snapshot
.show_home_button() ?
314 IDS_RESET_PROFILE_SETTINGS_SHOW_HOME_BUTTON_TRUE
:
315 IDS_RESET_PROFILE_SETTINGS_SHOW_HOME_BUTTON_FALSE
;
318 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHOW_HOME_BUTTON
),
319 l10n_util::GetStringUTF16(show_home_button_id
));
321 TemplateURLService
* service
=
322 TemplateURLServiceFactory::GetForProfile(profile
);
324 TemplateURL
* dse
= service
->GetDefaultSearchProvider();
327 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_DSE
),
328 dse
->GenerateSearchURL(service
->search_terms_data()).host());
331 if (snapshot
.shortcuts_determined()) {
332 base::string16 shortcut_targets
;
333 const std::vector
<ShortcutCommand
>& shortcuts
= snapshot
.shortcuts();
334 for (std::vector
<ShortcutCommand
>::const_iterator i
=
335 shortcuts
.begin(); i
!= shortcuts
.end(); ++i
) {
336 if (!shortcut_targets
.empty())
337 shortcut_targets
+= base::ASCIIToUTF16("\n");
338 shortcut_targets
+= base::ASCIIToUTF16("chrome.exe ");
339 shortcut_targets
+= i
->second
;
341 if (!shortcut_targets
.empty()) {
343 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHORTCUTS
),
348 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHORTCUTS
),
349 l10n_util::GetStringUTF16(
350 IDS_RESET_PROFILE_SETTINGS_PROCESSING_SHORTCUTS
));
353 const ResettableSettingsSnapshot::ExtensionList
& extensions
=
354 snapshot
.enabled_extensions();
355 std::string extension_names
;
356 for (ResettableSettingsSnapshot::ExtensionList::const_iterator i
=
357 extensions
.begin(); i
!= extensions
.end(); ++i
) {
358 if (!extension_names
.empty())
359 extension_names
+= '\n';
360 extension_names
+= i
->second
;
362 if (!extension_names
.empty()) {
364 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_EXTENSIONS
),