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