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/synchronization/cancellation_flag.h"
11 #include "base/values.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/feedback/feedback_data.h"
15 #include "chrome/browser/feedback/feedback_util.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/search_engines/template_url_service.h"
18 #include "chrome/browser/search_engines/template_url_service_factory.h"
19 #include "chrome/common/chrome_content_client.h"
20 #include "chrome/common/chrome_version_info.h"
21 #include "chrome/common/pref_names.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "grit/generated_resources.h"
24 #include "grit/google_chrome_strings.h"
25 #include "ui/base/l10n/l10n_util.h"
29 // Feedback bucket labels.
30 const char kProfileResetPromptBucket
[] = "SamplingOfSettingsResetPrompt";
31 const char kProfileResetWebUIBucket
[] = "ProfileResetReport";
33 // Dictionary keys for feedback report.
34 const char kDefaultSearchEnginePath
[] = "default_search_engine";
35 const char kEnabledExtensions
[] = "enabled_extensions";
36 const char kHomepageIsNewTabPage
[] = "homepage_is_ntp";
37 const char kHomepagePath
[] = "homepage";
38 const char kShortcuts
[] = "shortcuts";
39 const char kStartupTypePath
[] = "startup_type";
40 const char kStartupURLPath
[] = "startup_urls";
42 template <class StringType
>
43 void AddPair(base::ListValue
* list
,
44 const base::string16
& key
,
45 const StringType
& value
) {
46 base::DictionaryValue
* results
= new base::DictionaryValue();
47 results
->SetString("key", key
);
48 results
->SetString("value", value
);
49 list
->Append(results
);
54 ResettableSettingsSnapshot::ResettableSettingsSnapshot(
56 : startup_(SessionStartupPref::GetStartupPref(profile
)),
57 shortcuts_determined_(false),
58 weak_ptr_factory_(this) {
59 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
60 // URLs are always stored sorted.
61 std::sort(startup_
.urls
.begin(), startup_
.urls
.end());
63 PrefService
* prefs
= profile
->GetPrefs();
65 homepage_
= prefs
->GetString(prefs::kHomePage
);
66 homepage_is_ntp_
= prefs
->GetBoolean(prefs::kHomePageIsNewTabPage
);
68 TemplateURLService
* service
=
69 TemplateURLServiceFactory::GetForProfile(profile
);
71 TemplateURL
* dse
= service
->GetDefaultSearchProvider();
73 dse_url_
= dse
->url();
75 ExtensionService
* extension_service
= profile
->GetExtensionService();
76 DCHECK(extension_service
);
77 const extensions::ExtensionSet
* enabled_ext
= extension_service
->extensions();
78 enabled_extensions_
.reserve(enabled_ext
->size());
80 for (extensions::ExtensionSet::const_iterator it
= enabled_ext
->begin();
81 it
!= enabled_ext
->end(); ++it
)
82 enabled_extensions_
.push_back(std::make_pair((*it
)->id(), (*it
)->name()));
84 // ExtensionSet is sorted but it seems to be an implementation detail.
85 std::sort(enabled_extensions_
.begin(), enabled_extensions_
.end());
88 ResettableSettingsSnapshot::~ResettableSettingsSnapshot() {
89 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
90 if (cancellation_flag_
)
91 cancellation_flag_
->data
.Set();
94 void ResettableSettingsSnapshot::Subtract(
95 const ResettableSettingsSnapshot
& snapshot
) {
96 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
97 ExtensionList extensions
= base::STLSetDifference
<ExtensionList
>(
98 enabled_extensions_
, snapshot
.enabled_extensions_
);
99 enabled_extensions_
.swap(extensions
);
102 int ResettableSettingsSnapshot::FindDifferentFields(
103 const ResettableSettingsSnapshot
& snapshot
) const {
104 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
107 if (startup_
.type
!= snapshot
.startup_
.type
||
108 startup_
.urls
!= snapshot
.startup_
.urls
)
109 bit_mask
|= STARTUP_MODE
;
111 if (homepage_is_ntp_
!= snapshot
.homepage_is_ntp_
||
112 homepage_
!= snapshot
.homepage_
)
113 bit_mask
|= HOMEPAGE
;
115 if (dse_url_
!= snapshot
.dse_url_
)
118 if (enabled_extensions_
!= snapshot
.enabled_extensions_
)
119 bit_mask
|= EXTENSIONS
;
121 if (shortcuts_
!= snapshot
.shortcuts_
)
122 bit_mask
|= SHORTCUTS
;
124 COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS
== 31,
130 void ResettableSettingsSnapshot::RequestShortcuts(
131 const base::Closure
& callback
) {
132 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
133 DCHECK(!cancellation_flag_
&& !shortcuts_determined());
135 cancellation_flag_
= new SharedCancellationFlag
;
136 content::BrowserThread::PostTaskAndReplyWithResult(
137 content::BrowserThread::FILE,
139 base::Bind(&GetChromeLaunchShortcuts
, cancellation_flag_
),
140 base::Bind(&ResettableSettingsSnapshot::SetShortcutsAndReport
,
141 weak_ptr_factory_
.GetWeakPtr(),
145 void ResettableSettingsSnapshot::SetShortcutsAndReport(
146 const base::Closure
& callback
,
147 const std::vector
<ShortcutCommand
>& shortcuts
) {
148 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
149 shortcuts_
= shortcuts
;
150 shortcuts_determined_
= true;
151 cancellation_flag_
= NULL
;
153 if (!callback
.is_null())
157 std::string
SerializeSettingsReport(const ResettableSettingsSnapshot
& snapshot
,
159 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
160 base::DictionaryValue dict
;
162 if (field_mask
& ResettableSettingsSnapshot::STARTUP_MODE
) {
163 base::ListValue
* list
= new base::ListValue
;
164 const std::vector
<GURL
>& urls
= snapshot
.startup_urls();
165 for (std::vector
<GURL
>::const_iterator i
= urls
.begin();
166 i
!= urls
.end(); ++i
)
167 list
->AppendString(i
->spec());
168 dict
.Set(kStartupURLPath
, list
);
169 dict
.SetInteger(kStartupTypePath
, snapshot
.startup_type());
172 if (field_mask
& ResettableSettingsSnapshot::HOMEPAGE
) {
173 dict
.SetString(kHomepagePath
, snapshot
.homepage());
174 dict
.SetBoolean(kHomepageIsNewTabPage
, snapshot
.homepage_is_ntp());
177 if (field_mask
& ResettableSettingsSnapshot::DSE_URL
)
178 dict
.SetString(kDefaultSearchEnginePath
, snapshot
.dse_url());
180 if (field_mask
& ResettableSettingsSnapshot::EXTENSIONS
) {
181 base::ListValue
* list
= new base::ListValue
;
182 const ResettableSettingsSnapshot::ExtensionList
& extensions
=
183 snapshot
.enabled_extensions();
184 for (ResettableSettingsSnapshot::ExtensionList::const_iterator i
=
185 extensions
.begin(); i
!= extensions
.end(); ++i
) {
186 // Replace "\"" to simplify server-side analysis.
187 std::string ext_name
;
188 base::ReplaceChars(i
->second
, "\"", "\'", &ext_name
);
189 list
->AppendString(i
->first
+ ";" + ext_name
);
191 dict
.Set(kEnabledExtensions
, list
);
194 if (field_mask
& ResettableSettingsSnapshot::SHORTCUTS
) {
195 base::ListValue
* list
= new base::ListValue
;
196 const std::vector
<ShortcutCommand
>& shortcuts
= snapshot
.shortcuts();
197 for (std::vector
<ShortcutCommand
>::const_iterator i
= shortcuts
.begin();
198 i
!= shortcuts
.end(); ++i
) {
199 base::string16 arguments
;
200 // Replace "\"" to simplify server-side analysis.
201 base::ReplaceChars(i
->second
, base::ASCIIToUTF16("\"").c_str(),
202 base::ASCIIToUTF16("\'"), &arguments
);
203 list
->AppendString(arguments
);
205 dict
.Set(kShortcuts
, list
);
208 COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS
== 31,
209 serialize_new_field_here
);
212 base::JSONWriter::Write(&dict
, &json
);
216 void SendSettingsFeedback(const std::string
& report
,
218 SnapshotCaller caller
) {
219 scoped_refptr
<FeedbackData
> feedback_data
= new FeedbackData();
222 case PROFILE_RESET_WEBUI
:
223 bucket
= kProfileResetWebUIBucket
;
225 case PROFILE_RESET_PROMPT
:
226 bucket
= kProfileResetPromptBucket
;
229 feedback_data
->set_category_tag(bucket
);
230 feedback_data
->set_description(report
);
232 feedback_data
->set_image(make_scoped_ptr(new std::string
));
233 feedback_data
->set_profile(profile
);
235 feedback_data
->set_page_url("");
236 feedback_data
->set_user_email("");
238 feedback_util::SendReport(feedback_data
);
241 scoped_ptr
<base::ListValue
> GetReadableFeedbackForSnapshot(
243 const ResettableSettingsSnapshot
& snapshot
) {
245 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
246 scoped_ptr
<base::ListValue
> list(new base::ListValue
);
248 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_LOCALE
),
249 g_browser_process
->GetApplicationLocale());
251 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_USER_AGENT
),
253 chrome::VersionInfo version_info
;
254 std::string version
= version_info
.Version();
255 version
+= chrome::VersionInfo::GetVersionStringModifier();
257 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME
),
260 // Add snapshot data.
261 const std::vector
<GURL
>& urls
= snapshot
.startup_urls();
262 std::string startup_urls
;
263 for (std::vector
<GURL
>::const_iterator i
= urls
.begin();
264 i
!= urls
.end(); ++i
) {
265 if (!startup_urls
.empty())
267 startup_urls
+= i
->host();
269 if (!startup_urls
.empty()) {
271 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_URLS
),
275 base::string16 startup_type
;
276 switch (snapshot
.startup_type()) {
277 case SessionStartupPref::DEFAULT
:
278 startup_type
= l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_NEWTAB
);
280 case SessionStartupPref::LAST
:
281 startup_type
= l10n_util::GetStringUTF16(
282 IDS_OPTIONS_STARTUP_RESTORE_LAST_SESSION
);
284 case SessionStartupPref::URLS
:
285 startup_type
= l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_PAGES
);
291 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_TYPE
),
294 if (!snapshot
.homepage().empty()) {
296 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE
),
297 snapshot
.homepage());
300 int is_ntp_message_id
= snapshot
.homepage_is_ntp() ?
301 IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_TRUE
:
302 IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_FALSE
;
304 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP
),
305 l10n_util::GetStringUTF16(is_ntp_message_id
));
307 TemplateURLService
* service
=
308 TemplateURLServiceFactory::GetForProfile(profile
);
310 TemplateURL
* dse
= service
->GetDefaultSearchProvider();
313 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_DSE
),
314 TemplateURLService::GenerateSearchURL(dse
).host());
317 if (snapshot
.shortcuts_determined()) {
318 base::string16 shortcut_targets
;
319 const std::vector
<ShortcutCommand
>& shortcuts
= snapshot
.shortcuts();
320 for (std::vector
<ShortcutCommand
>::const_iterator i
=
321 shortcuts
.begin(); i
!= shortcuts
.end(); ++i
) {
322 if (!shortcut_targets
.empty())
323 shortcut_targets
+= base::ASCIIToUTF16("\n");
324 shortcut_targets
+= base::ASCIIToUTF16("chrome.exe ");
325 shortcut_targets
+= i
->second
;
327 if (!shortcut_targets
.empty()) {
329 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHORTCUTS
),
334 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHORTCUTS
),
335 l10n_util::GetStringUTF16(
336 IDS_RESET_PROFILE_SETTINGS_PROCESSING_SHORTCUTS
));
339 const ResettableSettingsSnapshot::ExtensionList
& extensions
=
340 snapshot
.enabled_extensions();
341 std::string extension_names
;
342 for (ResettableSettingsSnapshot::ExtensionList::const_iterator i
=
343 extensions
.begin(); i
!= extensions
.end(); ++i
) {
344 if (!extension_names
.empty())
345 extension_names
+= '\n';
346 extension_names
+= i
->second
;
348 if (!extension_names
.empty()) {
350 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_EXTENSIONS
),