1 // Copyright 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/automatic_profile_resetter_delegate.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/logging.h"
14 #include "base/memory/scoped_vector.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/values.h"
18 #include "chrome/app/chrome_command_ids.h"
19 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/google/google_brand.h"
21 #include "chrome/browser/profile_resetter/brandcode_config_fetcher.h"
22 #include "chrome/browser/profile_resetter/profile_reset_global_error.h"
23 #include "chrome/browser/profile_resetter/profile_resetter.h"
24 #include "chrome/browser/profile_resetter/resettable_settings_snapshot.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/search_engines/template_url_service_factory.h"
27 #include "chrome/browser/ui/browser.h"
28 #include "chrome/browser/ui/browser_finder.h"
29 #include "chrome/browser/ui/global_error/global_error_service.h"
30 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
31 #include "components/search_engines/template_url_prepopulate_data.h"
32 #include "components/search_engines/template_url_service.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/notification_service.h"
37 #include "chrome/browser/enumerate_modules_model_win.h"
42 scoped_ptr
<base::DictionaryValue
> BuildSubTreeFromTemplateURL(
43 const TemplateURL
* template_url
) {
44 // If this value contains a placeholder in the pre-populated data, it will
45 // have been replaced as it was loaded into a TemplateURL.
46 // BuildSubTreeFromTemplateURL works with TemplateURL (not TemplateURLData)
47 // in order to maintain this behaviour.
48 // TODO(engedy): Confirm the expected behaviour and convert to use
49 // TemplateURLData if possible."
50 scoped_ptr
<base::DictionaryValue
> tree(new base::DictionaryValue
);
51 tree
->SetString("name", template_url
->short_name());
52 tree
->SetString("short_name", template_url
->short_name());
53 tree
->SetString("keyword", template_url
->keyword());
54 tree
->SetString("search_url", template_url
->url());
55 tree
->SetString("url", template_url
->url());
56 tree
->SetString("suggestions_url", template_url
->suggestions_url());
57 tree
->SetString("instant_url", template_url
->instant_url());
58 tree
->SetString("image_url", template_url
->image_url());
59 tree
->SetString("new_tab_url", template_url
->new_tab_url());
60 tree
->SetString("search_url_post_params",
61 template_url
->search_url_post_params());
62 tree
->SetString("suggestions_url_post_params",
63 template_url
->suggestions_url_post_params());
64 tree
->SetString("instant_url_post_params",
65 template_url
->instant_url_post_params());
66 tree
->SetString("image_url_post_params",
67 template_url
->image_url_post_params());
68 base::ListValue
* alternate_urls
= new base::ListValue
;
69 alternate_urls
->AppendStrings(template_url
->alternate_urls());
70 tree
->Set("alternate_urls", alternate_urls
);
71 tree
->SetString("favicon_url", template_url
->favicon_url().spec());
72 tree
->SetString("originating_url", template_url
->originating_url().spec());
73 tree
->SetBoolean("safe_for_autoreplace",
74 template_url
->safe_for_autoreplace());
75 base::ListValue
* input_encodings
= new base::ListValue
;
76 input_encodings
->AppendStrings(template_url
->input_encodings());
77 tree
->Set("input_encodings", input_encodings
);
78 tree
->SetString("id", base::Int64ToString(template_url
->id()));
79 tree
->SetString("date_created",
81 template_url
->date_created().ToInternalValue()));
82 tree
->SetString("last_modified",
84 template_url
->last_modified().ToInternalValue()));
85 tree
->SetBoolean("created_by_policy", template_url
->created_by_policy());
86 tree
->SetInteger("usage_count", template_url
->usage_count());
87 tree
->SetInteger("prepopulate_id", template_url
->prepopulate_id());
88 tree
->SetString("search_terms_replacement_key",
89 template_url
->search_terms_replacement_key());
94 void ExtractLoadedModuleNameDigests(
95 const base::ListValue
& module_list
,
96 base::ListValue
* module_name_digests
) {
97 DCHECK(module_name_digests
);
99 // EnumerateModulesModel produces a list of dictionaries.
100 // Each dictionary corresponds to a module and exposes a number of properties.
101 // We care only about 'type' and 'name'.
102 for (size_t i
= 0; i
< module_list
.GetSize(); ++i
) {
103 const base::DictionaryValue
* module_dictionary
= NULL
;
104 if (!module_list
.GetDictionary(i
, &module_dictionary
))
106 ModuleEnumerator::ModuleType module_type
=
107 ModuleEnumerator::LOADED_MODULE
;
108 if (!module_dictionary
->GetInteger(
109 "type", reinterpret_cast<int*>(&module_type
)) ||
110 module_type
!= ModuleEnumerator::LOADED_MODULE
) {
113 std::string module_name
;
114 if (!module_dictionary
->GetString("name", &module_name
))
116 module_name
= base::ToLowerASCII(module_name
);
117 module_name_digests
->AppendString(base::MD5String(module_name
));
125 // AutomaticProfileResetterDelegateImpl --------------------------------------
127 AutomaticProfileResetterDelegateImpl::AutomaticProfileResetterDelegateImpl(
129 ProfileResetter::ResettableFlags resettable_aspects
)
131 global_error_service_(GlobalErrorServiceFactory::GetForProfile(profile_
)),
132 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile_
)),
133 resettable_aspects_(resettable_aspects
) {
135 if (template_url_service_
) {
136 template_url_service_
->AddObserver(this);
137 // Needed so that |template_url_service_ready_event_| will be signaled even
138 // when TemplateURLService had been already initialized before this point.
139 OnTemplateURLServiceChanged();
143 module_list_
.reset(EnumerateModulesModel::GetInstance()->GetModuleList());
146 // Having a non-empty module list proves that enumeration had been already
147 // performed before this point.
148 modules_have_been_enumerated_event_
.Signal();
151 chrome::NOTIFICATION_MODULE_LIST_ENUMERATED
,
152 content::NotificationService::AllSources());
155 AutomaticProfileResetterDelegateImpl::~AutomaticProfileResetterDelegateImpl() {
156 if (template_url_service_
)
157 template_url_service_
->RemoveObserver(this);
160 void AutomaticProfileResetterDelegateImpl::EnumerateLoadedModulesIfNeeded() {
161 if (!modules_have_been_enumerated_event_
.is_signaled()) {
163 EnumerateModulesModel::GetInstance()->ScanNow();
165 modules_have_been_enumerated_event_
.Signal();
170 void AutomaticProfileResetterDelegateImpl::
171 RequestCallbackWhenLoadedModulesAreEnumerated(
172 const base::Closure
& ready_callback
) const {
173 DCHECK(!ready_callback
.is_null());
174 modules_have_been_enumerated_event_
.Post(FROM_HERE
, ready_callback
);
177 void AutomaticProfileResetterDelegateImpl::LoadTemplateURLServiceIfNeeded() {
178 DCHECK(template_url_service_
);
179 template_url_service_
->Load(); // Safe to call even if it has loaded already.
182 void AutomaticProfileResetterDelegateImpl::
183 RequestCallbackWhenTemplateURLServiceIsLoaded(
184 const base::Closure
& ready_callback
) const {
185 DCHECK(!ready_callback
.is_null());
186 template_url_service_ready_event_
.Post(FROM_HERE
, ready_callback
);
189 void AutomaticProfileResetterDelegateImpl::
190 FetchBrandcodedDefaultSettingsIfNeeded() {
191 if (brandcoded_config_fetcher_
||
192 brandcoded_defaults_fetched_event_
.is_signaled())
195 std::string brandcode
;
196 google_brand::GetBrand(&brandcode
);
197 if (brandcode
.empty()) {
198 brandcoded_defaults_
.reset(new BrandcodedDefaultSettings
);
199 brandcoded_defaults_fetched_event_
.Signal();
201 brandcoded_config_fetcher_
.reset(new BrandcodeConfigFetcher(
203 &AutomaticProfileResetterDelegateImpl::OnBrandcodedDefaultsFetched
,
204 base::Unretained(this)),
205 GURL("https://tools.google.com/service/update2"),
210 void AutomaticProfileResetterDelegateImpl::
211 RequestCallbackWhenBrandcodedDefaultsAreFetched(
212 const base::Closure
& ready_callback
) const {
213 DCHECK(!ready_callback
.is_null());
214 brandcoded_defaults_fetched_event_
.Post(FROM_HERE
, ready_callback
);
217 scoped_ptr
<base::ListValue
> AutomaticProfileResetterDelegateImpl::
218 GetLoadedModuleNameDigests() const {
219 DCHECK(modules_have_been_enumerated_event_
.is_signaled());
220 scoped_ptr
<base::ListValue
> result(new base::ListValue
);
223 ExtractLoadedModuleNameDigests(*module_list_
, result
.get());
225 return result
.Pass();
228 scoped_ptr
<base::DictionaryValue
> AutomaticProfileResetterDelegateImpl::
229 GetDefaultSearchProviderDetails() const {
230 DCHECK(template_url_service_
);
231 DCHECK(template_url_service_
->loaded());
233 const TemplateURL
* default_search_provider
=
234 template_url_service_
->GetDefaultSearchProvider();
236 // Having a NULL default search provider is due to either:
237 // 1.) default search providers being disabled by policy,
238 // 2.) directly tampering with the Preferences and/or the SQLite DBs.
239 // In this state, Omnibox non-keyword search functionality is disabled.
240 return default_search_provider
?
241 BuildSubTreeFromTemplateURL(default_search_provider
) :
242 scoped_ptr
<base::DictionaryValue
>(new base::DictionaryValue
);
245 bool AutomaticProfileResetterDelegateImpl::
246 IsDefaultSearchProviderManaged() const {
247 DCHECK(template_url_service_
);
248 DCHECK(template_url_service_
->loaded());
249 return template_url_service_
->is_default_search_managed();
252 scoped_ptr
<base::ListValue
> AutomaticProfileResetterDelegateImpl::
253 GetPrepopulatedSearchProvidersDetails() const {
254 size_t default_search_index
= 0;
255 ScopedVector
<TemplateURLData
> engines(
256 TemplateURLPrepopulateData::GetPrepopulatedEngines(
257 profile_
->GetPrefs(), &default_search_index
));
258 scoped_ptr
<base::ListValue
> engines_details_list(new base::ListValue
);
259 for (ScopedVector
<TemplateURLData
>::const_iterator it
= engines
.begin();
260 it
!= engines
.end(); ++it
) {
261 TemplateURL
template_url(**it
);
262 engines_details_list
->Append(
263 BuildSubTreeFromTemplateURL(&template_url
).release());
265 return engines_details_list
.Pass();
268 bool AutomaticProfileResetterDelegateImpl::TriggerPrompt() {
269 DCHECK(global_error_service_
);
271 Browser
* browser
= chrome::FindTabbedBrowser(
272 profile_
, false /*match_original_profiles*/, chrome::GetActiveDesktop());
273 if (!browser
|| !ProfileResetGlobalError::IsSupportedOnPlatform(browser
))
276 ProfileResetGlobalError
* global_error
= new ProfileResetGlobalError(profile_
);
277 global_error_service_
->AddGlobalError(global_error
);
279 // Do not try to show bubble if another GlobalError is already showing one.
280 const GlobalErrorService::GlobalErrorList
& global_errors(
281 global_error_service_
->errors());
282 GlobalErrorService::GlobalErrorList::const_iterator it
;
283 for (it
= global_errors
.begin(); it
!= global_errors
.end(); ++it
) {
284 if ((*it
)->GetBubbleView())
287 if (it
== global_errors
.end())
288 global_error
->ShowBubbleView(browser
);
292 void AutomaticProfileResetterDelegateImpl::TriggerProfileSettingsReset(
294 const base::Closure
& completion
) {
295 DCHECK(!profile_resetter_
);
296 DCHECK(!completion
.is_null());
298 profile_resetter_
.reset(new ProfileResetter(profile_
));
299 FetchBrandcodedDefaultSettingsIfNeeded();
300 RequestCallbackWhenBrandcodedDefaultsAreFetched(base::Bind(
301 &AutomaticProfileResetterDelegateImpl::RunProfileSettingsReset
,
307 void AutomaticProfileResetterDelegateImpl::OnTemplateURLServiceChanged() {
308 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
309 DCHECK(template_url_service_
);
310 if (template_url_service_
->loaded() &&
311 !template_url_service_ready_event_
.is_signaled())
312 template_url_service_ready_event_
.Signal();
315 void AutomaticProfileResetterDelegateImpl::DismissPrompt() {
316 DCHECK(global_error_service_
);
317 GlobalError
* global_error
=
318 global_error_service_
->GetGlobalErrorByMenuItemCommandID(
319 IDC_SHOW_SETTINGS_RESET_BUBBLE
);
321 // This will also close/destroy the Bubble UI if it is currently shown.
322 global_error_service_
->RemoveGlobalError(global_error
);
327 void AutomaticProfileResetterDelegateImpl::Observe(
329 const content::NotificationSource
& source
,
330 const content::NotificationDetails
& details
) {
331 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
332 if (type
== chrome::NOTIFICATION_MODULE_LIST_ENUMERATED
&&
333 !modules_have_been_enumerated_event_
.is_signaled()) {
335 module_list_
.reset(EnumerateModulesModel::GetInstance()->GetModuleList());
337 modules_have_been_enumerated_event_
.Signal();
341 void AutomaticProfileResetterDelegateImpl::SendFeedback(
342 const std::string
& report
) const {
343 SendSettingsFeedback(report
, profile_
, PROFILE_RESET_PROMPT
);
346 void AutomaticProfileResetterDelegateImpl::RunProfileSettingsReset(
348 const base::Closure
& completion
) {
349 DCHECK(brandcoded_defaults_
);
350 scoped_ptr
<ResettableSettingsSnapshot
> old_settings_snapshot
;
352 old_settings_snapshot
.reset(new ResettableSettingsSnapshot(profile_
));
353 old_settings_snapshot
->RequestShortcuts(base::Closure());
355 profile_resetter_
->Reset(resettable_aspects_
,
356 brandcoded_defaults_
.Pass(),
358 base::Bind(&AutomaticProfileResetterDelegateImpl::
359 OnProfileSettingsResetCompleted
,
362 base::Passed(&old_settings_snapshot
)));
365 void AutomaticProfileResetterDelegateImpl::
366 OnBrandcodedDefaultsFetched() {
367 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
368 DCHECK(brandcoded_config_fetcher_
);
369 DCHECK(!brandcoded_config_fetcher_
->IsActive());
370 brandcoded_defaults_
= brandcoded_config_fetcher_
->GetSettings();
371 if (!brandcoded_defaults_
)
372 brandcoded_defaults_
.reset(new BrandcodedDefaultSettings
);
373 brandcoded_defaults_fetched_event_
.Signal();
376 void AutomaticProfileResetterDelegateImpl::OnProfileSettingsResetCompleted(
377 const base::Closure
& user_callback
,
378 scoped_ptr
<ResettableSettingsSnapshot
> old_settings_snapshot
) {
379 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
380 if (old_settings_snapshot
) {
381 ResettableSettingsSnapshot
new_settings_snapshot(profile_
);
383 old_settings_snapshot
->FindDifferentFields(new_settings_snapshot
);
385 old_settings_snapshot
->Subtract(new_settings_snapshot
);
387 SerializeSettingsReport(*old_settings_snapshot
, difference
);
388 SendFeedback(report
);
391 content::BrowserThread::PostTask(
392 content::BrowserThread::UI
, FROM_HERE
, user_callback
);