Home | History | Annotate | Download | only in profile_resetter
      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_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"
     35 
     36 #if defined(OS_WIN)
     37 #include "chrome/browser/enumerate_modules_model_win.h"
     38 #endif
     39 
     40 namespace {
     41 
     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();
     73 }
     74 
     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);
     80 
     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;
     94     }
     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));
    100   }
    101 }
    102 #endif
    103 
    104 }  // namespace
    105 
    106 
    107 // AutomaticProfileResetterDelegateImpl --------------------------------------
    108 
    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();
    122   }
    123 
    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();
    131   }
    132   registrar_.Add(this,
    133                  chrome::NOTIFICATION_MODULE_LIST_ENUMERATED,
    134                  content::NotificationService::AllSources());
    135 }
    136 
    137 AutomaticProfileResetterDelegateImpl::~AutomaticProfileResetterDelegateImpl() {
    138   if (template_url_service_)
    139     template_url_service_->RemoveObserver(this);
    140 }
    141 
    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
    149   }
    150 }
    151 
    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);
    157 }
    158 
    159 void AutomaticProfileResetterDelegateImpl::LoadTemplateURLServiceIfNeeded() {
    160   DCHECK(template_url_service_);
    161   template_url_service_->Load();  // Safe to call even if it has loaded already.
    162 }
    163 
    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);
    169 }
    170 
    171 void AutomaticProfileResetterDelegateImpl::
    172     FetchBrandcodedDefaultSettingsIfNeeded() {
    173   if (brandcoded_config_fetcher_ ||
    174       brandcoded_defaults_fetched_event_.is_signaled())
    175     return;
    176 
    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));
    189   }
    190 }
    191 
    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);
    197 }
    198 
    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();
    208 }
    209 
    210 scoped_ptr<base::DictionaryValue> AutomaticProfileResetterDelegateImpl::
    211     GetDefaultSearchProviderDetails() const {
    212   DCHECK(template_url_service_);
    213   DCHECK(template_url_service_->loaded());
    214 
    215   const TemplateURL* default_search_provider =
    216       template_url_service_->GetDefaultSearchProvider();
    217 
    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);
    225 }
    226 
    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();
    232 }
    233 
    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();
    245 }
    246 
    247 bool AutomaticProfileResetterDelegateImpl::TriggerPrompt() {
    248   DCHECK(global_error_service_);
    249 
    250   if (!ProfileResetGlobalError::IsSupportedOnPlatform())
    251     return false;
    252 
    253   ProfileResetGlobalError* global_error = new ProfileResetGlobalError(profile_);
    254   global_error_service_->AddGlobalError(global_error);
    255 
    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;
    263   }
    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);
    271   }
    272   return true;
    273 }
    274 
    275 void AutomaticProfileResetterDelegateImpl::TriggerProfileSettingsReset(
    276     bool send_feedback,
    277     const base::Closure& completion) {
    278   DCHECK(!profile_resetter_);
    279   DCHECK(!completion.is_null());
    280 
    281   profile_resetter_.reset(new ProfileResetter(profile_));
    282   FetchBrandcodedDefaultSettingsIfNeeded();
    283   RequestCallbackWhenBrandcodedDefaultsAreFetched(base::Bind(
    284       &AutomaticProfileResetterDelegateImpl::RunProfileSettingsReset,
    285       AsWeakPtr(),
    286       send_feedback,
    287       completion));
    288 }
    289 
    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();
    296 }
    297 
    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;
    307   }
    308 }
    309 
    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();
    321   }
    322 }
    323 
    324 void AutomaticProfileResetterDelegateImpl::SendFeedback(
    325     const std::string& report) const {
    326   SendSettingsFeedback(report, profile_, PROFILE_RESET_PROMPT);
    327 }
    328 
    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)));
    343 }
    344 
    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();
    354 }
    355 
    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);
    369     }
    370   }
    371   content::BrowserThread::PostTask(
    372       content::BrowserThread::UI, FROM_HERE, user_callback);
    373 }
    374