• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/profile_resetter/automatic_profile_resetter_delegate.h"
6 
7 #include <string>
8 
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_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"
35 
36 #if defined(OS_WIN)
37 #include "chrome/browser/enumerate_modules_model_win.h"
38 #endif
39 
40 namespace {
41 
BuildSubTreeFromTemplateURL(const TemplateURL * template_url)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();
91 }
92 
93 #if defined(OS_WIN)
ExtractLoadedModuleNameDigests(const base::ListValue & module_list,base::ListValue * module_name_digests)94 void ExtractLoadedModuleNameDigests(
95     const base::ListValue& module_list,
96     base::ListValue* module_name_digests) {
97   DCHECK(module_name_digests);
98 
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;
112     }
113     std::string module_name;
114     if (!module_dictionary->GetString("name", &module_name))
115       continue;
116     StringToLowerASCII(&module_name);
117     module_name_digests->AppendString(base::MD5String(module_name));
118   }
119 }
120 #endif
121 
122 }  // namespace
123 
124 
125 // AutomaticProfileResetterDelegateImpl --------------------------------------
126 
AutomaticProfileResetterDelegateImpl(Profile * profile,ProfileResetter::ResettableFlags resettable_aspects)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();
140   }
141 
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();
149   }
150   registrar_.Add(this,
151                  chrome::NOTIFICATION_MODULE_LIST_ENUMERATED,
152                  content::NotificationService::AllSources());
153 }
154 
~AutomaticProfileResetterDelegateImpl()155 AutomaticProfileResetterDelegateImpl::~AutomaticProfileResetterDelegateImpl() {
156   if (template_url_service_)
157     template_url_service_->RemoveObserver(this);
158 }
159 
EnumerateLoadedModulesIfNeeded()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
167   }
168 }
169 
170 void AutomaticProfileResetterDelegateImpl::
RequestCallbackWhenLoadedModulesAreEnumerated(const base::Closure & ready_callback) const171     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);
175 }
176 
LoadTemplateURLServiceIfNeeded()177 void AutomaticProfileResetterDelegateImpl::LoadTemplateURLServiceIfNeeded() {
178   DCHECK(template_url_service_);
179   template_url_service_->Load();  // Safe to call even if it has loaded already.
180 }
181 
182 void AutomaticProfileResetterDelegateImpl::
RequestCallbackWhenTemplateURLServiceIsLoaded(const base::Closure & ready_callback) const183     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);
187 }
188 
189 void AutomaticProfileResetterDelegateImpl::
FetchBrandcodedDefaultSettingsIfNeeded()190     FetchBrandcodedDefaultSettingsIfNeeded() {
191   if (brandcoded_config_fetcher_ ||
192       brandcoded_defaults_fetched_event_.is_signaled())
193     return;
194 
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));
207   }
208 }
209 
210 void AutomaticProfileResetterDelegateImpl::
RequestCallbackWhenBrandcodedDefaultsAreFetched(const base::Closure & ready_callback) const211     RequestCallbackWhenBrandcodedDefaultsAreFetched(
212     const base::Closure& ready_callback) const {
213   DCHECK(!ready_callback.is_null());
214   brandcoded_defaults_fetched_event_.Post(FROM_HERE, ready_callback);
215 }
216 
217 scoped_ptr<base::ListValue> AutomaticProfileResetterDelegateImpl::
GetLoadedModuleNameDigests() const218     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();
226 }
227 
228 scoped_ptr<base::DictionaryValue> AutomaticProfileResetterDelegateImpl::
GetDefaultSearchProviderDetails() const229     GetDefaultSearchProviderDetails() const {
230   DCHECK(template_url_service_);
231   DCHECK(template_url_service_->loaded());
232 
233   const TemplateURL* default_search_provider =
234       template_url_service_->GetDefaultSearchProvider();
235 
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);
243 }
244 
245 bool AutomaticProfileResetterDelegateImpl::
IsDefaultSearchProviderManaged() const246     IsDefaultSearchProviderManaged() const {
247   DCHECK(template_url_service_);
248   DCHECK(template_url_service_->loaded());
249   return template_url_service_->is_default_search_managed();
250 }
251 
252 scoped_ptr<base::ListValue> AutomaticProfileResetterDelegateImpl::
GetPrepopulatedSearchProvidersDetails() const253     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());
264   }
265   return engines_details_list.Pass();
266 }
267 
TriggerPrompt()268 bool AutomaticProfileResetterDelegateImpl::TriggerPrompt() {
269   DCHECK(global_error_service_);
270 
271   if (!ProfileResetGlobalError::IsSupportedOnPlatform())
272     return false;
273 
274   ProfileResetGlobalError* global_error = new ProfileResetGlobalError(profile_);
275   global_error_service_->AddGlobalError(global_error);
276 
277   // Do not try to show bubble if another GlobalError is already showing one.
278   const GlobalErrorService::GlobalErrorList& global_errors(
279       global_error_service_->errors());
280   GlobalErrorService::GlobalErrorList::const_iterator it;
281   for (it = global_errors.begin(); it != global_errors.end(); ++it) {
282     if ((*it)->GetBubbleView())
283       break;
284   }
285   if (it == global_errors.end()) {
286     Browser* browser = chrome::FindTabbedBrowser(
287         profile_,
288         false /*match_original_profiles*/,
289         chrome::GetActiveDesktop());
290     if (browser)
291       global_error->ShowBubbleView(browser);
292   }
293   return true;
294 }
295 
TriggerProfileSettingsReset(bool send_feedback,const base::Closure & completion)296 void AutomaticProfileResetterDelegateImpl::TriggerProfileSettingsReset(
297     bool send_feedback,
298     const base::Closure& completion) {
299   DCHECK(!profile_resetter_);
300   DCHECK(!completion.is_null());
301 
302   profile_resetter_.reset(new ProfileResetter(profile_));
303   FetchBrandcodedDefaultSettingsIfNeeded();
304   RequestCallbackWhenBrandcodedDefaultsAreFetched(base::Bind(
305       &AutomaticProfileResetterDelegateImpl::RunProfileSettingsReset,
306       AsWeakPtr(),
307       send_feedback,
308       completion));
309 }
310 
OnTemplateURLServiceChanged()311 void AutomaticProfileResetterDelegateImpl::OnTemplateURLServiceChanged() {
312   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
313   DCHECK(template_url_service_);
314   if (template_url_service_->loaded() &&
315       !template_url_service_ready_event_.is_signaled())
316     template_url_service_ready_event_.Signal();
317 }
318 
DismissPrompt()319 void AutomaticProfileResetterDelegateImpl::DismissPrompt() {
320   DCHECK(global_error_service_);
321   GlobalError* global_error =
322       global_error_service_->GetGlobalErrorByMenuItemCommandID(
323           IDC_SHOW_SETTINGS_RESET_BUBBLE);
324   if (global_error) {
325     // This will also close/destroy the Bubble UI if it is currently shown.
326     global_error_service_->RemoveGlobalError(global_error);
327     delete global_error;
328   }
329 }
330 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)331 void AutomaticProfileResetterDelegateImpl::Observe(
332     int type,
333     const content::NotificationSource& source,
334     const content::NotificationDetails& details) {
335   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
336   if (type == chrome::NOTIFICATION_MODULE_LIST_ENUMERATED &&
337       !modules_have_been_enumerated_event_.is_signaled()) {
338 #if defined(OS_WIN)
339     module_list_.reset(EnumerateModulesModel::GetInstance()->GetModuleList());
340 #endif
341     modules_have_been_enumerated_event_.Signal();
342   }
343 }
344 
SendFeedback(const std::string & report) const345 void AutomaticProfileResetterDelegateImpl::SendFeedback(
346     const std::string& report) const {
347   SendSettingsFeedback(report, profile_, PROFILE_RESET_PROMPT);
348 }
349 
RunProfileSettingsReset(bool send_feedback,const base::Closure & completion)350 void AutomaticProfileResetterDelegateImpl::RunProfileSettingsReset(
351     bool send_feedback,
352     const base::Closure& completion) {
353   DCHECK(brandcoded_defaults_);
354   scoped_ptr<ResettableSettingsSnapshot> old_settings_snapshot;
355   if (send_feedback) {
356     old_settings_snapshot.reset(new ResettableSettingsSnapshot(profile_));
357     old_settings_snapshot->RequestShortcuts(base::Closure());
358   }
359   profile_resetter_->Reset(resettable_aspects_,
360                            brandcoded_defaults_.Pass(),
361                            send_feedback,
362                            base::Bind(&AutomaticProfileResetterDelegateImpl::
363                                           OnProfileSettingsResetCompleted,
364                                       AsWeakPtr(),
365                                       completion,
366                                       base::Passed(&old_settings_snapshot)));
367 }
368 
369 void AutomaticProfileResetterDelegateImpl::
OnBrandcodedDefaultsFetched()370     OnBrandcodedDefaultsFetched() {
371   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
372   DCHECK(brandcoded_config_fetcher_);
373   DCHECK(!brandcoded_config_fetcher_->IsActive());
374   brandcoded_defaults_ = brandcoded_config_fetcher_->GetSettings();
375   if (!brandcoded_defaults_)
376     brandcoded_defaults_.reset(new BrandcodedDefaultSettings);
377   brandcoded_defaults_fetched_event_.Signal();
378 }
379 
OnProfileSettingsResetCompleted(const base::Closure & user_callback,scoped_ptr<ResettableSettingsSnapshot> old_settings_snapshot)380 void AutomaticProfileResetterDelegateImpl::OnProfileSettingsResetCompleted(
381     const base::Closure& user_callback,
382     scoped_ptr<ResettableSettingsSnapshot> old_settings_snapshot) {
383   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
384   if (old_settings_snapshot) {
385     ResettableSettingsSnapshot new_settings_snapshot(profile_);
386     int difference =
387         old_settings_snapshot->FindDifferentFields(new_settings_snapshot);
388     if (difference) {
389       old_settings_snapshot->Subtract(new_settings_snapshot);
390       std::string report =
391           SerializeSettingsReport(*old_settings_snapshot, difference);
392       SendFeedback(report);
393     }
394   }
395   content::BrowserThread::PostTask(
396       content::BrowserThread::UI, FROM_HERE, user_callback);
397 }
398