Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / profile_resetter / automatic_profile_resetter_delegate.cc
blobb120f7cdcd4b3fe9f021e73c1328172cb3b4d364
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_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"
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 // 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",
80 base::Int64ToString(
81 template_url->date_created().ToInternalValue()));
82 tree->SetString("last_modified",
83 base::Int64ToString(
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());
90 return tree.Pass();
93 #if defined(OS_WIN)
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))
105 continue;
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) {
111 continue;
113 std::string module_name;
114 if (!module_dictionary->GetString("name", &module_name))
115 continue;
116 base::StringToLowerASCII(&module_name);
117 module_name_digests->AppendString(base::MD5String(module_name));
120 #endif
122 } // namespace
125 // AutomaticProfileResetterDelegateImpl --------------------------------------
127 AutomaticProfileResetterDelegateImpl::AutomaticProfileResetterDelegateImpl(
128 Profile* profile,
129 ProfileResetter::ResettableFlags resettable_aspects)
130 : profile_(profile),
131 global_error_service_(GlobalErrorServiceFactory::GetForProfile(profile_)),
132 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile_)),
133 resettable_aspects_(resettable_aspects) {
134 DCHECK(profile_);
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();
142 #if defined(OS_WIN)
143 module_list_.reset(EnumerateModulesModel::GetInstance()->GetModuleList());
144 #endif
145 if (module_list_) {
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();
150 registrar_.Add(this,
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()) {
162 #if defined(OS_WIN)
163 EnumerateModulesModel::GetInstance()->ScanNow();
164 #else
165 modules_have_been_enumerated_event_.Signal();
166 #endif
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())
193 return;
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();
200 } else {
201 brandcoded_config_fetcher_.reset(new BrandcodeConfigFetcher(
202 base::Bind(
203 &AutomaticProfileResetterDelegateImpl::OnBrandcodedDefaultsFetched,
204 base::Unretained(this)),
205 GURL("https://tools.google.com/service/update2"),
206 brandcode));
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);
221 #if defined(OS_WIN)
222 if (module_list_)
223 ExtractLoadedModuleNameDigests(*module_list_, result.get());
224 #endif
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))
274 return false;
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())
285 break;
287 if (it == global_errors.end())
288 global_error->ShowBubbleView(browser);
289 return true;
292 void AutomaticProfileResetterDelegateImpl::TriggerProfileSettingsReset(
293 bool send_feedback,
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,
302 AsWeakPtr(),
303 send_feedback,
304 completion));
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);
320 if (global_error) {
321 // This will also close/destroy the Bubble UI if it is currently shown.
322 global_error_service_->RemoveGlobalError(global_error);
323 delete global_error;
327 void AutomaticProfileResetterDelegateImpl::Observe(
328 int type,
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()) {
334 #if defined(OS_WIN)
335 module_list_.reset(EnumerateModulesModel::GetInstance()->GetModuleList());
336 #endif
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(
347 bool send_feedback,
348 const base::Closure& completion) {
349 DCHECK(brandcoded_defaults_);
350 scoped_ptr<ResettableSettingsSnapshot> old_settings_snapshot;
351 if (send_feedback) {
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(),
357 send_feedback,
358 base::Bind(&AutomaticProfileResetterDelegateImpl::
359 OnProfileSettingsResetCompleted,
360 AsWeakPtr(),
361 completion,
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_);
382 int difference =
383 old_settings_snapshot->FindDifferentFields(new_settings_snapshot);
384 if (difference) {
385 old_settings_snapshot->Subtract(new_settings_snapshot);
386 std::string report =
387 SerializeSettingsReport(*old_settings_snapshot, difference);
388 SendFeedback(report);
391 content::BrowserThread::PostTask(
392 content::BrowserThread::UI, FROM_HERE, user_callback);