Home | History | Annotate | Download | only in profile_resetter
      1 // Copyright (c) 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/profile_resetter.h"
      6 
      7 #include <string>
      8 
      9 #include "base/prefs/pref_service.h"
     10 #include "base/prefs/scoped_user_pref_update.h"
     11 #include "base/synchronization/cancellation_flag.h"
     12 #include "chrome/browser/browser_process.h"
     13 #include "chrome/browser/browsing_data/browsing_data_helper.h"
     14 #include "chrome/browser/content_settings/host_content_settings_map.h"
     15 #include "chrome/browser/extensions/extension_service.h"
     16 #include "chrome/browser/google/google_url_tracker_factory.h"
     17 #include "chrome/browser/profile_resetter/brandcoded_default_settings.h"
     18 #include "chrome/browser/profiles/profile.h"
     19 #include "chrome/browser/search_engines/template_url_prepopulate_data.h"
     20 #include "chrome/browser/search_engines/template_url_service.h"
     21 #include "chrome/browser/search_engines/template_url_service_factory.h"
     22 #include "chrome/browser/ui/browser.h"
     23 #include "chrome/browser/ui/browser_iterator.h"
     24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     25 #include "chrome/common/pref_names.h"
     26 #include "chrome/installer/util/browser_distribution.h"
     27 #include "components/google/core/browser/google_pref_names.h"
     28 #include "components/google/core/browser/google_url_tracker.h"
     29 #include "content/public/browser/browser_thread.h"
     30 #include "extensions/browser/extension_system.h"
     31 #include "extensions/browser/management_policy.h"
     32 
     33 #if defined(OS_WIN)
     34 #include "base/base_paths.h"
     35 #include "base/path_service.h"
     36 #include "chrome/browser/component_updater/sw_reporter_installer_win.h"
     37 #include "chrome/installer/util/shell_util.h"
     38 
     39 namespace {
     40 
     41 void ResetShortcutsOnFileThread() {
     42   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
     43   // Get full path of chrome.
     44   base::FilePath chrome_exe;
     45   if (!PathService::Get(base::FILE_EXE, &chrome_exe))
     46     return;
     47   BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
     48       BrowserDistribution::CHROME_BROWSER);
     49   for (int location = ShellUtil::SHORTCUT_LOCATION_FIRST;
     50        location < ShellUtil::NUM_SHORTCUT_LOCATIONS; ++location) {
     51     ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
     52         static_cast<ShellUtil::ShortcutLocation>(location),
     53         dist,
     54         ShellUtil::CURRENT_USER,
     55         chrome_exe,
     56         true,
     57         NULL,
     58         NULL);
     59   }
     60 }
     61 
     62 }  // namespace
     63 #endif  // defined(OS_WIN)
     64 
     65 ProfileResetter::ProfileResetter(Profile* profile)
     66     : profile_(profile),
     67       template_url_service_(TemplateURLServiceFactory::GetForProfile(profile_)),
     68       pending_reset_flags_(0),
     69       cookies_remover_(NULL),
     70       weak_ptr_factory_(this) {
     71   DCHECK(CalledOnValidThread());
     72   DCHECK(profile_);
     73 }
     74 
     75 ProfileResetter::~ProfileResetter() {
     76   if (cookies_remover_)
     77     cookies_remover_->RemoveObserver(this);
     78 }
     79 
     80 void ProfileResetter::Reset(
     81     ProfileResetter::ResettableFlags resettable_flags,
     82     scoped_ptr<BrandcodedDefaultSettings> master_settings,
     83     bool accepted_send_feedback,
     84     const base::Closure& callback) {
     85   DCHECK(CalledOnValidThread());
     86   DCHECK(master_settings);
     87 
     88   // We should never be called with unknown flags.
     89   CHECK_EQ(static_cast<ResettableFlags>(0), resettable_flags & ~ALL);
     90 
     91   // We should never be called when a previous reset has not finished.
     92   CHECK_EQ(static_cast<ResettableFlags>(0), pending_reset_flags_);
     93 
     94   if (!resettable_flags) {
     95     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
     96                                      callback);
     97     return;
     98   }
     99 
    100   master_settings_.swap(master_settings);
    101   callback_ = callback;
    102 
    103   // These flags are set to false by the individual reset functions.
    104   pending_reset_flags_ = resettable_flags;
    105 
    106   struct {
    107     Resettable flag;
    108     void (ProfileResetter::*method)();
    109   } flagToMethod[] = {
    110         {DEFAULT_SEARCH_ENGINE, &ProfileResetter::ResetDefaultSearchEngine},
    111         {HOMEPAGE, &ProfileResetter::ResetHomepage},
    112         {CONTENT_SETTINGS, &ProfileResetter::ResetContentSettings},
    113         {COOKIES_AND_SITE_DATA, &ProfileResetter::ResetCookiesAndSiteData},
    114         {EXTENSIONS, &ProfileResetter::ResetExtensions},
    115         {STARTUP_PAGES, &ProfileResetter::ResetStartupPages},
    116         {PINNED_TABS, &ProfileResetter::ResetPinnedTabs},
    117         {SHORTCUTS, &ProfileResetter::ResetShortcuts},
    118     };
    119 
    120   ResettableFlags reset_triggered_for_flags = 0;
    121   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(flagToMethod); ++i) {
    122     if (resettable_flags & flagToMethod[i].flag) {
    123       reset_triggered_for_flags |= flagToMethod[i].flag;
    124       (this->*flagToMethod[i].method)();
    125     }
    126   }
    127 
    128 // When the user resets any of their settings on Windows and agreed to sending
    129 // feedback, run the software reporter tool to see if it could find the reason
    130 // why the user wanted a reset.
    131 #if defined(OS_WIN)
    132   // The browser process and / or local_state can be NULL when running tests.
    133   if (accepted_send_feedback && g_browser_process &&
    134       g_browser_process->local_state() &&
    135       g_browser_process->local_state()->GetBoolean(
    136           prefs::kMetricsReportingEnabled)) {
    137     ExecuteSwReporter(g_browser_process->component_updater(),
    138                       g_browser_process->local_state());
    139   }
    140 #endif
    141 
    142   DCHECK_EQ(resettable_flags, reset_triggered_for_flags);
    143 }
    144 
    145 bool ProfileResetter::IsActive() const {
    146   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    147   return pending_reset_flags_ != 0;
    148 }
    149 
    150 void ProfileResetter::MarkAsDone(Resettable resettable) {
    151   DCHECK(CalledOnValidThread());
    152 
    153   // Check that we are never called twice or unexpectedly.
    154   CHECK(pending_reset_flags_ & resettable);
    155 
    156   pending_reset_flags_ &= ~resettable;
    157 
    158   if (!pending_reset_flags_) {
    159     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
    160                                      callback_);
    161     callback_.Reset();
    162     master_settings_.reset();
    163     template_url_service_sub_.reset();
    164   }
    165 }
    166 
    167 void ProfileResetter::ResetDefaultSearchEngine() {
    168   DCHECK(CalledOnValidThread());
    169   DCHECK(template_url_service_);
    170   // If TemplateURLServiceFactory is ready we can clean it right now.
    171   // Otherwise, load it and continue from ProfileResetter::Observe.
    172   if (template_url_service_->loaded()) {
    173     PrefService* prefs = profile_->GetPrefs();
    174     DCHECK(prefs);
    175     TemplateURLPrepopulateData::ClearPrepopulatedEnginesInPrefs(
    176         profile_->GetPrefs());
    177     scoped_ptr<base::ListValue> search_engines(
    178         master_settings_->GetSearchProviderOverrides());
    179     if (search_engines) {
    180       // This Chrome distribution channel provides a custom search engine. We
    181       // must reset to it.
    182       ListPrefUpdate update(prefs, prefs::kSearchProviderOverrides);
    183       update->Swap(search_engines.get());
    184     }
    185 
    186     template_url_service_->RepairPrepopulatedSearchEngines();
    187 
    188     // Reset Google search URL.
    189     prefs->ClearPref(prefs::kLastPromptedGoogleURL);
    190     const TemplateURL* default_search_provider =
    191         template_url_service_->GetDefaultSearchProvider();
    192     if (default_search_provider &&
    193         default_search_provider->HasGoogleBaseURLs(
    194             template_url_service_->search_terms_data())) {
    195       GoogleURLTracker* tracker =
    196           GoogleURLTrackerFactory::GetForProfile(profile_);
    197       if (tracker)
    198         tracker->RequestServerCheck(true);
    199     }
    200 
    201     MarkAsDone(DEFAULT_SEARCH_ENGINE);
    202   } else {
    203     template_url_service_sub_ =
    204         template_url_service_->RegisterOnLoadedCallback(
    205             base::Bind(&ProfileResetter::OnTemplateURLServiceLoaded,
    206                        weak_ptr_factory_.GetWeakPtr()));
    207     template_url_service_->Load();
    208   }
    209 }
    210 
    211 void ProfileResetter::ResetHomepage() {
    212   DCHECK(CalledOnValidThread());
    213   PrefService* prefs = profile_->GetPrefs();
    214   DCHECK(prefs);
    215   std::string homepage;
    216   bool homepage_is_ntp, show_home_button;
    217 
    218   if (master_settings_->GetHomepage(&homepage))
    219     prefs->SetString(prefs::kHomePage, homepage);
    220 
    221   if (master_settings_->GetHomepageIsNewTab(&homepage_is_ntp))
    222     prefs->SetBoolean(prefs::kHomePageIsNewTabPage, homepage_is_ntp);
    223   else
    224     prefs->ClearPref(prefs::kHomePageIsNewTabPage);
    225 
    226   if (master_settings_->GetShowHomeButton(&show_home_button))
    227     prefs->SetBoolean(prefs::kShowHomeButton, show_home_button);
    228   else
    229     prefs->ClearPref(prefs::kShowHomeButton);
    230   MarkAsDone(HOMEPAGE);
    231 }
    232 
    233 void ProfileResetter::ResetContentSettings() {
    234   DCHECK(CalledOnValidThread());
    235   PrefService* prefs = profile_->GetPrefs();
    236   HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
    237 
    238   for (int type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
    239     map->ClearSettingsForOneType(static_cast<ContentSettingsType>(type));
    240     if (HostContentSettingsMap::IsSettingAllowedForType(
    241             prefs,
    242             CONTENT_SETTING_DEFAULT,
    243             static_cast<ContentSettingsType>(type)))
    244       map->SetDefaultContentSetting(static_cast<ContentSettingsType>(type),
    245                                     CONTENT_SETTING_DEFAULT);
    246   }
    247   MarkAsDone(CONTENT_SETTINGS);
    248 }
    249 
    250 void ProfileResetter::ResetCookiesAndSiteData() {
    251   DCHECK(CalledOnValidThread());
    252   DCHECK(!cookies_remover_);
    253 
    254   cookies_remover_ = BrowsingDataRemover::CreateForUnboundedRange(profile_);
    255   cookies_remover_->AddObserver(this);
    256   int remove_mask = BrowsingDataRemover::REMOVE_SITE_DATA |
    257                     BrowsingDataRemover::REMOVE_CACHE;
    258   PrefService* prefs = profile_->GetPrefs();
    259   DCHECK(prefs);
    260   // Don't try to clear LSO data if it's not supported.
    261   if (!prefs->GetBoolean(prefs::kClearPluginLSODataEnabled))
    262     remove_mask &= ~BrowsingDataRemover::REMOVE_PLUGIN_DATA;
    263   cookies_remover_->Remove(remove_mask, BrowsingDataHelper::UNPROTECTED_WEB);
    264 }
    265 
    266 void ProfileResetter::ResetExtensions() {
    267   DCHECK(CalledOnValidThread());
    268 
    269   std::vector<std::string> brandcode_extensions;
    270   master_settings_->GetExtensions(&brandcode_extensions);
    271 
    272   ExtensionService* extension_service = profile_->GetExtensionService();
    273   DCHECK(extension_service);
    274   extension_service->DisableUserExtensions(brandcode_extensions);
    275 
    276   MarkAsDone(EXTENSIONS);
    277 }
    278 
    279 void ProfileResetter::ResetStartupPages() {
    280   DCHECK(CalledOnValidThread());
    281   PrefService* prefs = profile_->GetPrefs();
    282   DCHECK(prefs);
    283   scoped_ptr<base::ListValue> url_list(
    284       master_settings_->GetUrlsToRestoreOnStartup());
    285   if (url_list)
    286     ListPrefUpdate(prefs, prefs::kURLsToRestoreOnStartup)->Swap(url_list.get());
    287 
    288   int restore_on_startup;
    289   if (master_settings_->GetRestoreOnStartup(&restore_on_startup))
    290     prefs->SetInteger(prefs::kRestoreOnStartup, restore_on_startup);
    291   else
    292     prefs->ClearPref(prefs::kRestoreOnStartup);
    293 
    294   prefs->SetBoolean(prefs::kRestoreOnStartupMigrated, true);
    295   MarkAsDone(STARTUP_PAGES);
    296 }
    297 
    298 void ProfileResetter::ResetPinnedTabs() {
    299   // Unpin all the tabs.
    300   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
    301     if (it->is_type_tabbed() && it->profile() == profile_) {
    302       TabStripModel* tab_model = it->tab_strip_model();
    303       // Here we assume that indexof(any mini tab) < indexof(any normal tab).
    304       // If we unpin the tab, it can be moved to the right. Thus traversing in
    305       // reverse direction is correct.
    306       for (int i = tab_model->count() - 1; i >= 0; --i) {
    307         if (tab_model->IsTabPinned(i) && !tab_model->IsAppTab(i))
    308           tab_model->SetTabPinned(i, false);
    309       }
    310     }
    311   }
    312   MarkAsDone(PINNED_TABS);
    313 }
    314 
    315 void ProfileResetter::ResetShortcuts() {
    316 #if defined(OS_WIN)
    317   content::BrowserThread::PostTaskAndReply(
    318       content::BrowserThread::FILE,
    319       FROM_HERE,
    320       base::Bind(&ResetShortcutsOnFileThread),
    321       base::Bind(&ProfileResetter::MarkAsDone,
    322                  weak_ptr_factory_.GetWeakPtr(),
    323                  SHORTCUTS));
    324 #else
    325   MarkAsDone(SHORTCUTS);
    326 #endif
    327 }
    328 
    329 void ProfileResetter::OnTemplateURLServiceLoaded() {
    330   // TemplateURLService has loaded. If we need to clean search engines, it's
    331   // time to go on.
    332   DCHECK(CalledOnValidThread());
    333   template_url_service_sub_.reset();
    334   if (pending_reset_flags_ & DEFAULT_SEARCH_ENGINE)
    335     ResetDefaultSearchEngine();
    336 }
    337 
    338 void ProfileResetter::OnBrowsingDataRemoverDone() {
    339   cookies_remover_ = NULL;
    340   MarkAsDone(COOKIES_AND_SITE_DATA);
    341 }
    342 
    343 std::vector<ShortcutCommand> GetChromeLaunchShortcuts(
    344     const scoped_refptr<SharedCancellationFlag>& cancel) {
    345   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
    346 #if defined(OS_WIN)
    347   // Get full path of chrome.
    348   base::FilePath chrome_exe;
    349   if (!PathService::Get(base::FILE_EXE, &chrome_exe))
    350     return std::vector<ShortcutCommand>();
    351   BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
    352       BrowserDistribution::CHROME_BROWSER);
    353   std::vector<ShortcutCommand> shortcuts;
    354   for (int location = ShellUtil::SHORTCUT_LOCATION_FIRST;
    355        location < ShellUtil::NUM_SHORTCUT_LOCATIONS; ++location) {
    356     if (cancel && cancel->data.IsSet())
    357       break;
    358     ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
    359         static_cast<ShellUtil::ShortcutLocation>(location),
    360         dist,
    361         ShellUtil::CURRENT_USER,
    362         chrome_exe,
    363         false,
    364         cancel,
    365         &shortcuts);
    366   }
    367   return shortcuts;
    368 #else
    369   return std::vector<ShortcutCommand>();
    370 #endif
    371 }
    372