Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / profile_resetter / automatic_profile_resetter_delegate.cc
blob63e49209c318e9c07ee888a2f3451ae0d4d5880a
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"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/logging.h"
13 #include "base/md5.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_util.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_prepopulate_data.h"
27 #include "chrome/browser/search_engines/template_url_service.h"
28 #include "chrome/browser/search_engines/template_url_service_factory.h"
29 #include "chrome/browser/ui/browser.h"
30 #include "chrome/browser/ui/browser_finder.h"
31 #include "chrome/browser/ui/global_error/global_error_service.h"
32 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/notification_service.h"
36 #if defined(OS_WIN)
37 #include "chrome/browser/enumerate_modules_model_win.h"
38 #endif
40 namespace {
42 scoped_ptr<base::DictionaryValue> BuildSubTreeFromTemplateURL(
43 const TemplateURL* template_url) {
44 scoped_ptr<base::DictionaryValue> tree(new base::DictionaryValue);
45 tree->SetString("search_url", template_url->url());
46 tree->SetString("search_terms_replacement_key",
47 template_url->search_terms_replacement_key());
48 tree->SetString("suggest_url", template_url->suggestions_url());
49 tree->SetString("instant_url", template_url->instant_url());
50 tree->SetString("image_url", template_url->image_url());
51 tree->SetString("new_tab_url", template_url->new_tab_url());
52 tree->SetString("search_url_post_params",
53 template_url->search_url_post_params());
54 tree->SetString("suggest_url_post_params",
55 template_url->suggestions_url_post_params());
56 tree->SetString("instant_url_post_params",
57 template_url->instant_url_post_params());
58 tree->SetString("image_url_post_params",
59 template_url->image_url_post_params());
60 tree->SetString("icon_url", template_url->favicon_url().spec());
61 tree->SetString("name", template_url->short_name());
62 tree->SetString("keyword", template_url->keyword());
63 base::ListValue* input_encodings = new base::ListValue;
64 input_encodings->AppendStrings(template_url->input_encodings());
65 tree->Set("encodings", input_encodings);
66 tree->SetString("id", base::Int64ToString(template_url->id()));
67 tree->SetString("prepopulate_id",
68 base::IntToString(template_url->prepopulate_id()));
69 base::ListValue* alternate_urls = new base::ListValue;
70 alternate_urls->AppendStrings(template_url->alternate_urls());
71 tree->Set("alternate_urls", alternate_urls);
72 return tree.Pass();
75 #if defined(OS_WIN)
76 void ExtractLoadedModuleNameDigests(
77 const base::ListValue& module_list,
78 base::ListValue* module_name_digests) {
79 DCHECK(module_name_digests);
81 // EnumerateModulesModel produces a list of dictionaries.
82 // Each dictionary corresponds to a module and exposes a number of properties.
83 // We care only about 'type' and 'name'.
84 for (size_t i = 0; i < module_list.GetSize(); ++i) {
85 const base::DictionaryValue* module_dictionary = NULL;
86 if (!module_list.GetDictionary(i, &module_dictionary))
87 continue;
88 ModuleEnumerator::ModuleType module_type =
89 ModuleEnumerator::LOADED_MODULE;
90 if (!module_dictionary->GetInteger(
91 "type", reinterpret_cast<int*>(&module_type)) ||
92 module_type != ModuleEnumerator::LOADED_MODULE) {
93 continue;
95 std::string module_name;
96 if (!module_dictionary->GetString("name", &module_name))
97 continue;
98 StringToLowerASCII(&module_name);
99 module_name_digests->AppendString(base::MD5String(module_name));
102 #endif
104 } // namespace
107 // AutomaticProfileResetterDelegateImpl --------------------------------------
109 AutomaticProfileResetterDelegateImpl::AutomaticProfileResetterDelegateImpl(
110 Profile* profile,
111 ProfileResetter::ResettableFlags resettable_aspects)
112 : profile_(profile),
113 global_error_service_(GlobalErrorServiceFactory::GetForProfile(profile_)),
114 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile_)),
115 resettable_aspects_(resettable_aspects) {
116 DCHECK(profile_);
117 if (template_url_service_) {
118 template_url_service_->AddObserver(this);
119 // Needed so that |template_url_service_ready_event_| will be signaled even
120 // when TemplateURLService had been already initialized before this point.
121 OnTemplateURLServiceChanged();
124 #if defined(OS_WIN)
125 module_list_.reset(EnumerateModulesModel::GetInstance()->GetModuleList());
126 #endif
127 if (module_list_) {
128 // Having a non-empty module list proves that enumeration had been already
129 // performed before this point.
130 modules_have_been_enumerated_event_.Signal();
132 registrar_.Add(this,
133 chrome::NOTIFICATION_MODULE_LIST_ENUMERATED,
134 content::NotificationService::AllSources());
137 AutomaticProfileResetterDelegateImpl::~AutomaticProfileResetterDelegateImpl() {
138 if (template_url_service_)
139 template_url_service_->RemoveObserver(this);
142 void AutomaticProfileResetterDelegateImpl::EnumerateLoadedModulesIfNeeded() {
143 if (!modules_have_been_enumerated_event_.is_signaled()) {
144 #if defined(OS_WIN)
145 EnumerateModulesModel::GetInstance()->ScanNow();
146 #else
147 modules_have_been_enumerated_event_.Signal();
148 #endif
152 void AutomaticProfileResetterDelegateImpl::
153 RequestCallbackWhenLoadedModulesAreEnumerated(
154 const base::Closure& ready_callback) const {
155 DCHECK(!ready_callback.is_null());
156 modules_have_been_enumerated_event_.Post(FROM_HERE, ready_callback);
159 void AutomaticProfileResetterDelegateImpl::LoadTemplateURLServiceIfNeeded() {
160 DCHECK(template_url_service_);
161 template_url_service_->Load(); // Safe to call even if it has loaded already.
164 void AutomaticProfileResetterDelegateImpl::
165 RequestCallbackWhenTemplateURLServiceIsLoaded(
166 const base::Closure& ready_callback) const {
167 DCHECK(!ready_callback.is_null());
168 template_url_service_ready_event_.Post(FROM_HERE, ready_callback);
171 void AutomaticProfileResetterDelegateImpl::
172 FetchBrandcodedDefaultSettingsIfNeeded() {
173 if (brandcoded_config_fetcher_ ||
174 brandcoded_defaults_fetched_event_.is_signaled())
175 return;
177 std::string brandcode;
178 google_util::GetBrand(&brandcode);
179 if (brandcode.empty()) {
180 brandcoded_defaults_.reset(new BrandcodedDefaultSettings);
181 brandcoded_defaults_fetched_event_.Signal();
182 } else {
183 brandcoded_config_fetcher_.reset(new BrandcodeConfigFetcher(
184 base::Bind(
185 &AutomaticProfileResetterDelegateImpl::OnBrandcodedDefaultsFetched,
186 base::Unretained(this)),
187 GURL("https://tools.google.com/service/update2"),
188 brandcode));
192 void AutomaticProfileResetterDelegateImpl::
193 RequestCallbackWhenBrandcodedDefaultsAreFetched(
194 const base::Closure& ready_callback) const {
195 DCHECK(!ready_callback.is_null());
196 brandcoded_defaults_fetched_event_.Post(FROM_HERE, ready_callback);
199 scoped_ptr<base::ListValue> AutomaticProfileResetterDelegateImpl::
200 GetLoadedModuleNameDigests() const {
201 DCHECK(modules_have_been_enumerated_event_.is_signaled());
202 scoped_ptr<base::ListValue> result(new base::ListValue);
203 #if defined(OS_WIN)
204 if (module_list_)
205 ExtractLoadedModuleNameDigests(*module_list_, result.get());
206 #endif
207 return result.Pass();
210 scoped_ptr<base::DictionaryValue> AutomaticProfileResetterDelegateImpl::
211 GetDefaultSearchProviderDetails() const {
212 DCHECK(template_url_service_);
213 DCHECK(template_url_service_->loaded());
215 const TemplateURL* default_search_provider =
216 template_url_service_->GetDefaultSearchProvider();
218 // Having a NULL default search provider is due to either:
219 // 1.) default search providers being disabled by policy,
220 // 2.) directly tampering with the Preferences and/or the SQLite DBs.
221 // In this state, Omnibox non-keyword search functionality is disabled.
222 return default_search_provider ?
223 BuildSubTreeFromTemplateURL(default_search_provider) :
224 scoped_ptr<base::DictionaryValue>(new base::DictionaryValue);
227 bool AutomaticProfileResetterDelegateImpl::
228 IsDefaultSearchProviderManaged() const {
229 DCHECK(template_url_service_);
230 DCHECK(template_url_service_->loaded());
231 return template_url_service_->is_default_search_managed();
234 scoped_ptr<base::ListValue> AutomaticProfileResetterDelegateImpl::
235 GetPrepopulatedSearchProvidersDetails() const {
236 size_t default_search_index = 0;
237 ScopedVector<TemplateURL> engines(
238 TemplateURLPrepopulateData::GetPrepopulatedEngines(
239 template_url_service_->profile(), &default_search_index));
240 scoped_ptr<base::ListValue> engines_details_list(new base::ListValue);
241 for (ScopedVector<TemplateURL>::const_iterator it = engines.begin();
242 it != engines.end(); ++it)
243 engines_details_list->Append(BuildSubTreeFromTemplateURL(*it).release());
244 return engines_details_list.Pass();
247 bool AutomaticProfileResetterDelegateImpl::TriggerPrompt() {
248 DCHECK(global_error_service_);
250 if (!ProfileResetGlobalError::IsSupportedOnPlatform())
251 return false;
253 ProfileResetGlobalError* global_error = new ProfileResetGlobalError(profile_);
254 global_error_service_->AddGlobalError(global_error);
256 // Do not try to show bubble if another GlobalError is already showing one.
257 const GlobalErrorService::GlobalErrorList& global_errors(
258 global_error_service_->errors());
259 GlobalErrorService::GlobalErrorList::const_iterator it;
260 for (it = global_errors.begin(); it != global_errors.end(); ++it) {
261 if ((*it)->GetBubbleView())
262 break;
264 if (it == global_errors.end()) {
265 Browser* browser = chrome::FindTabbedBrowser(
266 profile_,
267 false /*match_original_profiles*/,
268 chrome::GetActiveDesktop());
269 if (browser)
270 global_error->ShowBubbleView(browser);
272 return true;
275 void AutomaticProfileResetterDelegateImpl::TriggerProfileSettingsReset(
276 bool send_feedback,
277 const base::Closure& completion) {
278 DCHECK(!profile_resetter_);
279 DCHECK(!completion.is_null());
281 profile_resetter_.reset(new ProfileResetter(profile_));
282 FetchBrandcodedDefaultSettingsIfNeeded();
283 RequestCallbackWhenBrandcodedDefaultsAreFetched(base::Bind(
284 &AutomaticProfileResetterDelegateImpl::RunProfileSettingsReset,
285 AsWeakPtr(),
286 send_feedback,
287 completion));
290 void AutomaticProfileResetterDelegateImpl::OnTemplateURLServiceChanged() {
291 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
292 DCHECK(template_url_service_);
293 if (template_url_service_->loaded() &&
294 !template_url_service_ready_event_.is_signaled())
295 template_url_service_ready_event_.Signal();
298 void AutomaticProfileResetterDelegateImpl::DismissPrompt() {
299 DCHECK(global_error_service_);
300 GlobalError* global_error =
301 global_error_service_->GetGlobalErrorByMenuItemCommandID(
302 IDC_SHOW_SETTINGS_RESET_BUBBLE);
303 if (global_error) {
304 // This will also close/destroy the Bubble UI if it is currently shown.
305 global_error_service_->RemoveGlobalError(global_error);
306 delete global_error;
310 void AutomaticProfileResetterDelegateImpl::Observe(
311 int type,
312 const content::NotificationSource& source,
313 const content::NotificationDetails& details) {
314 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
315 if (type == chrome::NOTIFICATION_MODULE_LIST_ENUMERATED &&
316 !modules_have_been_enumerated_event_.is_signaled()) {
317 #if defined(OS_WIN)
318 module_list_.reset(EnumerateModulesModel::GetInstance()->GetModuleList());
319 #endif
320 modules_have_been_enumerated_event_.Signal();
324 void AutomaticProfileResetterDelegateImpl::SendFeedback(
325 const std::string& report) const {
326 SendSettingsFeedback(report, profile_, PROFILE_RESET_PROMPT);
329 void AutomaticProfileResetterDelegateImpl::RunProfileSettingsReset(
330 bool send_feedback,
331 const base::Closure& completion) {
332 DCHECK(brandcoded_defaults_);
333 scoped_ptr<ResettableSettingsSnapshot> old_settings_snapshot(
334 send_feedback ? new ResettableSettingsSnapshot(profile_) : NULL);
335 profile_resetter_->Reset(
336 resettable_aspects_,
337 brandcoded_defaults_.Pass(),
338 base::Bind(&AutomaticProfileResetterDelegateImpl::
339 OnProfileSettingsResetCompleted,
340 AsWeakPtr(),
341 completion,
342 base::Passed(&old_settings_snapshot)));
345 void AutomaticProfileResetterDelegateImpl::
346 OnBrandcodedDefaultsFetched() {
347 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
348 DCHECK(brandcoded_config_fetcher_);
349 DCHECK(!brandcoded_config_fetcher_->IsActive());
350 brandcoded_defaults_ = brandcoded_config_fetcher_->GetSettings();
351 if (!brandcoded_defaults_)
352 brandcoded_defaults_.reset(new BrandcodedDefaultSettings);
353 brandcoded_defaults_fetched_event_.Signal();
356 void AutomaticProfileResetterDelegateImpl::OnProfileSettingsResetCompleted(
357 const base::Closure& user_callback,
358 scoped_ptr<ResettableSettingsSnapshot> old_settings_snapshot) {
359 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
360 if (old_settings_snapshot) {
361 ResettableSettingsSnapshot new_settings_snapshot(profile_);
362 int difference =
363 old_settings_snapshot->FindDifferentFields(new_settings_snapshot);
364 if (difference) {
365 old_settings_snapshot->Subtract(new_settings_snapshot);
366 std::string report =
367 SerializeSettingsReport(*old_settings_snapshot, difference);
368 SendFeedback(report);
371 content::BrowserThread::PostTask(
372 content::BrowserThread::UI, FROM_HERE, user_callback);