New methods allow to
- delete prepopulated search engines from user prefs
- delete the default search engine from user prefs
- reset unmanaged and non-extension URLs to prepopulated list. 

New unit tests:
- TemplateURLPrepopulateDataTest.ClearProvidersFromPrefs
- TemplateURLServiceTest.ResetNonExtensionURLs
- TemplateURLServiceTest.ResetURLsWithManagedDefault

BUG=235037,244291

Review URL: https://chromiumcodereview.appspot.com/15572002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202869 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/profile_resetter/profile_resetter.cc b/chrome/browser/profile_resetter/profile_resetter.cc
index 95fbd4a..cb8aab3c 100644
--- a/chrome/browser/profile_resetter/profile_resetter.cc
+++ b/chrome/browser/profile_resetter/profile_resetter.cc
@@ -5,14 +5,24 @@
 #include "chrome/browser/profile_resetter/profile_resetter.h"
 
 #include "base/prefs/pref_service.h"
+#include "chrome/browser/google/google_url_tracker.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
+#include "chrome/browser/search_engines/template_url_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 
 ProfileResetter::ProfileResetter(Profile* profile)
     : profile_(profile),
+      template_url_service_(TemplateURLServiceFactory::GetForProfile(profile_)),
       pending_reset_flags_(0) {
   DCHECK(CalledOnValidThread());
+  DCHECK(profile_);
+  DCHECK(template_url_service_);
+  registrar_.Add(this, chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED,
+                 content::Source<TemplateURLService>(template_url_service_));
 }
 
 ProfileResetter::~ProfileResetter() {}
@@ -81,16 +91,32 @@
 
   pending_reset_flags_ &= ~resettable;
 
-  if (!pending_reset_flags_)
+  if (!pending_reset_flags_) {
     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
                                      callback_);
+    callback_.Reset();
+  }
 }
 
 void ProfileResetter::ResetDefaultSearchEngine() {
   DCHECK(CalledOnValidThread());
-  NOTIMPLEMENTED();
-  // TODO(battre/vabr): Implement
-  MarkAsDone(DEFAULT_SEARCH_ENGINE);
+
+  // If TemplateURLServiceFactory is ready we can clean it right now.
+  // Otherwise, load it and continue from ProfileResetter::Observe.
+  if (template_url_service_->loaded()) {
+    // Reset Google search URL.
+    PrefService* prefs = profile_->GetPrefs();
+    DCHECK(prefs);
+    prefs->ClearPref(prefs::kLastPromptedGoogleURL);
+    GoogleURLTracker::RequestServerCheck(profile_);
+
+    TemplateURLPrepopulateData::ClearPrepopulatedEnginesInPrefs(profile_);
+    template_url_service_->ResetNonExtensionURLs();
+
+    MarkAsDone(DEFAULT_SEARCH_ENGINE);
+  } else {
+    template_url_service_->Load();
+  }
 }
 
 void ProfileResetter::ResetHomepage() {
@@ -133,3 +159,13 @@
   prefs->SetBoolean(prefs::kRestoreOnStartupMigrated, true);
   MarkAsDone(STARTUP_PAGE);
 }
+
+void ProfileResetter::Observe(int type,
+                              const content::NotificationSource& source,
+                              const content::NotificationDetails& details) {
+  DCHECK(CalledOnValidThread());
+  // TemplateURLService has loaded. If we need to clean search engines, it's
+  // time to go on.
+  if (pending_reset_flags_ & DEFAULT_SEARCH_ENGINE)
+    ResetDefaultSearchEngine();
+}
diff --git a/chrome/browser/profile_resetter/profile_resetter.h b/chrome/browser/profile_resetter/profile_resetter.h
index 1030fb4..810ca5c 100644
--- a/chrome/browser/profile_resetter/profile_resetter.h
+++ b/chrome/browser/profile_resetter/profile_resetter.h
@@ -8,13 +8,17 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/threading/non_thread_safe.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 
 class Profile;
+class TemplateURLService;
 
 // This class allows resetting certain aspects of a profile to default values.
 // It is used in case the profile has been damaged due to malware or bad user
 // settings.
-class ProfileResetter : public base::NonThreadSafe {
+class ProfileResetter : public base::NonThreadSafe,
+                        public content::NotificationObserver {
  public:
   // Flags indicating what aspects of a profile shall be reset.
   enum Resettable {
@@ -43,7 +47,7 @@
                  type_ResettableFlags_doesnt_match_Resettable);
 
   explicit ProfileResetter(Profile* profile);
-  ~ProfileResetter();
+  virtual ~ProfileResetter();
 
   // Resets |resettable_flags| and calls |callback| on the UI thread on
   // completion. If |resettable_flags| contains EXTENSIONS, these are handled
@@ -66,7 +70,13 @@
   void ResetExtensions(ExtensionHandling extension_handling);
   void ResetStartPage();
 
+  // content::NotificationObserver:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
   Profile* profile_;
+  TemplateURLService* template_url_service_;
 
   // Flags of a Resetable indicating which reset operations we are still waiting
   // for.
@@ -75,6 +85,8 @@
   // Called on UI thread when reset has been completed.
   base::Closure callback_;
 
+  content::NotificationRegistrar registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(ProfileResetter);
 };
 
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index 2cb521b..53a4166 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -39,6 +39,7 @@
  protected:
   ProfileResetterTest();
   ~ProfileResetterTest();
+
   // testing::Test:
   virtual void SetUp() OVERRIDE;
   virtual void TearDown() OVERRIDE;
@@ -64,7 +65,6 @@
 }
 
 TEST_F(ProfileResetterTest, ResetDefaultSearchEngine) {
-  test_util_.VerifyLoad();
   resetter_->Reset(
       ProfileResetter::DEFAULT_SEARCH_ENGINE,
       ProfileResetter::DISABLE_EXTENSIONS,
@@ -144,7 +144,6 @@
 
 TEST_F(ProfileResetterTest, ResetExtensionsAll) {
   // mock_object_ is a StrictMock, so we verify that it is called only once.
-  test_util_.VerifyLoad();
   resetter_->Reset(
       ProfileResetter::ALL,
       ProfileResetter::UNINSTALL_EXTENSIONS,
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.cc b/chrome/browser/search_engines/template_url_prepopulate_data.cc
index 235f621..efbb266f 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data.cc
+++ b/chrome/browser/search_engines/template_url_prepopulate_data.cc
@@ -1197,6 +1197,16 @@
   }
 }
 
+void ClearPrepopulatedEnginesInPrefs(Profile* profile) {
+  if (!profile)
+    return;
+
+  PrefService* prefs = profile->GetPrefs();
+  DCHECK(prefs);
+  prefs->ClearPref(prefs::kSearchProviderOverrides);
+  prefs->ClearPref(prefs::kSearchProviderOverridesVersion);
+}
+
 // The caller owns the returned TemplateURL.
 TemplateURL* MakePrepopulatedTemplateURLFromPrepopulateEngine(
     Profile* profile,
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.h b/chrome/browser/search_engines/template_url_prepopulate_data.h
index 6bd7882..3d1fa43 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data.h
+++ b/chrome/browser/search_engines/template_url_prepopulate_data.h
@@ -54,6 +54,9 @@
                             std::vector<TemplateURL*>* t_urls,
                             size_t* default_search_provider_index);
 
+// Removes prepopulated engines and their version stored in user prefs.
+void ClearPrepopulatedEnginesInPrefs(Profile* profile);
+
 // Returns the default search provider specified by the prepopulate data.
 // The caller owns the returned value, which may be NULL.
 // If |profile| is NULL, any search provider overrides from the preferences are
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
index a11adf3..342f10fa 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
+++ b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
@@ -6,6 +6,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_vector.h"
 #include "base/utf_string_conversions.h"
+#include "chrome/browser/search_engines/prepopulated_engines.h"
 #include "chrome/browser/search_engines/search_terms_data.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_prepopulate_data.h"
@@ -181,6 +182,52 @@
   EXPECT_EQ(2u, t_urls.size());
 }
 
+TEST(TemplateURLPrepopulateDataTest, ClearProvidersFromPrefs) {
+  TestingProfile profile;
+  TestingPrefServiceSyncable* prefs = profile.GetTestingPrefService();
+  prefs->SetUserPref(prefs::kSearchProviderOverridesVersion,
+                     Value::CreateIntegerValue(1));
+  ListValue* overrides = new ListValue;
+  DictionaryValue* entry(new DictionaryValue);
+  // Set only the minimal required settings for a search provider configuration.
+  entry->SetString("name", "foo");
+  entry->SetString("keyword", "fook");
+  entry->SetString("search_url", "http://foo.com/s?q={searchTerms}");
+  entry->SetString("favicon_url", "http://foi.com/favicon.ico");
+  entry->SetString("encoding", "UTF-8");
+  entry->SetInteger("id", 1001);
+  overrides->Append(entry);
+  prefs->SetUserPref(prefs::kSearchProviderOverrides, overrides);
+
+  int version = TemplateURLPrepopulateData::GetDataVersion(prefs);
+  EXPECT_EQ(1, version);
+
+  // This call removes the above search engine.
+  TemplateURLPrepopulateData::ClearPrepopulatedEnginesInPrefs(&profile);
+
+  version = TemplateURLPrepopulateData::GetDataVersion(prefs);
+  EXPECT_EQ(TemplateURLPrepopulateData::kCurrentDataVersion, version);
+
+  ScopedVector<TemplateURL> t_urls;
+  size_t default_index;
+  TemplateURLPrepopulateData::GetPrepopulatedEngines(&profile, &t_urls.get(),
+                                                     &default_index);
+  ASSERT_FALSE(t_urls.empty());
+  for (size_t i = 0; i < t_urls.size(); ++i) {
+    EXPECT_NE(ASCIIToUTF16("foo"), t_urls[i]->short_name());
+    EXPECT_NE(ASCIIToUTF16("fook"), t_urls[i]->keyword());
+    EXPECT_NE("foi.com", t_urls[i]->favicon_url().host());
+    EXPECT_NE("foo.com", t_urls[i]->url_ref().GetHost());
+    EXPECT_NE(1001, t_urls[i]->prepopulate_id());
+  }
+  // Ensures the default URL is Google and has the optional fields filled.
+  EXPECT_EQ(ASCIIToUTF16("Google"), t_urls[default_index]->short_name());
+  EXPECT_FALSE(t_urls[default_index]->suggestions_url().empty());
+  EXPECT_FALSE(t_urls[default_index]->instant_url().empty());
+  EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
+      TemplateURLPrepopulateData::GetEngineType(t_urls[default_index]->url()));
+}
+
 // Verifies that built-in search providers are processed correctly.
 TEST(TemplateURLPrepopulateDataTest, ProvidersFromPrepopulated) {
   // Use United States.
diff --git a/chrome/browser/search_engines/template_url_service.cc b/chrome/browser/search_engines/template_url_service.cc
index 8c78bd35..7588369 100644
--- a/chrome/browser/search_engines/template_url_service.cc
+++ b/chrome/browser/search_engines/template_url_service.cc
@@ -671,6 +671,53 @@
   return FirstPotentialDefaultEngine(template_urls_);
 }
 
+void TemplateURLService::ResetNonExtensionURLs() {
+  // Can't clean DB if it hasn't been loaded.
+  DCHECK(loaded());
+  ClearDefaultProviderFromPrefs();
+
+  TemplateURLVector entries_to_process;
+  for (TemplateURLVector::const_iterator i = template_urls_.begin();
+       i != template_urls_.end(); ++i) {
+    if (!(*i)->IsExtensionKeyword())
+      entries_to_process.push_back(*i);
+  }
+  // Clear default provider to be able to delete it.
+  default_search_provider_ = NULL;
+  // Remove non-extension keywords.
+  for (TemplateURLVector::const_iterator i = entries_to_process.begin();
+       i != entries_to_process.end(); ++i)
+    RemoveNoNotify(*i);
+
+  // Store the remaining engines in entries_to_process and merge them with
+  // prepopulated ones.
+  entries_to_process.clear();
+  entries_to_process.swap(template_urls_);
+  provider_map_.reset(new SearchHostToURLsMap);
+  UIThreadSearchTermsData search_terms_data(profile_);
+  provider_map_->Init(TemplateURLVector(), search_terms_data);
+
+  TemplateURL* default_search_provider = NULL;
+  // Force GetSearchProvidersUsingLoadedEngines() to include the prepopulated
+  // engines in the list by claiming we are currently on version 0, ensuring
+  // that the prepopulate data version will be newer.
+  int new_resource_keyword_version = 0;
+  GetSearchProvidersUsingLoadedEngines(service_.get(), profile_,
+                                       &entries_to_process,
+                                       &default_search_provider,
+                                       &new_resource_keyword_version,
+                                       &pre_sync_deletes_);
+  // Setup search engines and a default one.
+  AddTemplateURLsAndSetupDefaultEngine(&entries_to_process,
+                                       default_search_provider);
+
+  if (new_resource_keyword_version)
+    service_->SetBuiltinKeywordVersion(new_resource_keyword_version);
+
+  EnsureDefaultSearchProviderExists();
+  NotifyObservers();
+}
+
 void TemplateURLService::AddObserver(TemplateURLServiceObserver* observer) {
   model_observers_.AddObserver(observer);
 }
@@ -714,7 +761,6 @@
   // initial_default_search_provider_ is only needed before we've finished
   // loading. Now that we've loaded we can nuke it.
   initial_default_search_provider_.reset();
-  is_default_search_managed_ = false;
 
   TemplateURLVector template_urls;
   TemplateURL* default_search_provider = NULL;
@@ -723,81 +769,7 @@
       &template_urls, &default_search_provider, &new_resource_keyword_version,
       &pre_sync_deletes_);
 
-  bool database_specified_a_default = (default_search_provider != NULL);
-
-  // Check if default search provider is now managed.
-  scoped_ptr<TemplateURL> default_from_prefs;
-  LoadDefaultSearchProviderFromPrefs(&default_from_prefs,
-                                     &is_default_search_managed_);
-
-  // Remove entries that were created because of policy as they may have
-  // changed since the database was saved.
-  RemoveProvidersCreatedByPolicy(&template_urls,
-                                 &default_search_provider,
-                                 default_from_prefs.get());
-
-  PatchMissingSyncGUIDs(&template_urls);
-
-  if (is_default_search_managed_) {
-    SetTemplateURLs(template_urls);
-
-    if (TemplateURLsHaveSamePrefs(default_search_provider,
-                                  default_from_prefs.get())) {
-      // The value from the preferences was previously stored in the database.
-      // Reuse it.
-    } else {
-      // The value from the preferences takes over.
-      default_search_provider = NULL;
-      if (default_from_prefs.get()) {
-        TemplateURLData data(default_from_prefs->data());
-        data.created_by_policy = true;
-        data.id = kInvalidTemplateURLID;
-        default_search_provider = new TemplateURL(profile_, data);
-        if (!AddNoNotify(default_search_provider, true))
-          default_search_provider = NULL;
-      }
-    }
-    // Note that this saves the default search provider to prefs.
-    if (!default_search_provider ||
-        (!default_search_provider->IsExtensionKeyword() &&
-         default_search_provider->SupportsReplacement())) {
-      bool success = SetDefaultSearchProviderNoNotify(default_search_provider);
-      DCHECK(success);
-    }
-  } else {
-    // If we had a managed default, replace it with the synced default if
-    // applicable, or the first provider of the list.
-    TemplateURL* synced_default = GetPendingSyncedDefaultSearchProvider();
-    if (synced_default) {
-      default_search_provider = synced_default;
-      pending_synced_default_search_ = false;
-    } else if (database_specified_a_default &&
-               default_search_provider == NULL) {
-      UMA_HISTOGRAM_ENUMERATION(kFirstPotentialEngineHistogramName,
-          FIRST_POTENTIAL_CALLSITE_ON_LOAD, FIRST_POTENTIAL_CALLSITE_MAX);
-      default_search_provider = FirstPotentialDefaultEngine(template_urls);
-    }
-
-    // If the default search provider existed previously, then just
-    // set the member variable. Otherwise, we'll set it using the method
-    // to ensure that it is saved properly after its id is set.
-    if (default_search_provider &&
-        (default_search_provider->id() != kInvalidTemplateURLID)) {
-      default_search_provider_ = default_search_provider;
-      default_search_provider = NULL;
-    }
-    SetTemplateURLs(template_urls);
-
-    if (default_search_provider) {
-      // Note that this saves the default search provider to prefs.
-      SetDefaultSearchProvider(default_search_provider);
-    } else {
-      // Always save the default search provider to prefs. That way we don't
-      // have to worry about it being out of sync.
-      if (default_search_provider_)
-        SaveDefaultSearchProviderToPrefs(default_search_provider_);
-    }
-  }
+  AddTemplateURLsAndSetupDefaultEngine(&template_urls, default_search_provider);
 
   // This initializes provider_map_ which should be done before
   // calling UpdateKeywordSearchTermsForURL.
@@ -811,26 +783,7 @@
   if (new_resource_keyword_version)
     service_->SetBuiltinKeywordVersion(new_resource_keyword_version);
 
-  if (!is_default_search_managed_) {
-    bool has_default_search_provider = default_search_provider_ != NULL &&
-        default_search_provider_->SupportsReplacement();
-    UMA_HISTOGRAM_BOOLEAN(kHasDSPHistogramName,
-                          has_default_search_provider);
-    // Ensure that default search provider exists. See http://crbug.com/116952.
-    if (!has_default_search_provider) {
-      bool success =
-          SetDefaultSearchProviderNoNotify(FindNewDefaultSearchProvider());
-      DCHECK(success);
-    }
-    // Don't log anything if the user has a NULL default search provider. A
-    // logged value of 0 indicates a custom default search provider.
-    if (default_search_provider_) {
-      UMA_HISTOGRAM_ENUMERATION(
-          kDSPHistogramName,
-          default_search_provider_->prepopulate_id(),
-          TemplateURLPrepopulateData::kMaxPrepopulatedEngineID);
-    }
-  }
+  EnsureDefaultSearchProviderExists();
 
   NotifyObservers();
   NotifyLoaded();
@@ -1721,6 +1674,16 @@
   return true;
 }
 
+void TemplateURLService::ClearDefaultProviderFromPrefs() {
+  // We overwrite user preferences. If the default search engine is managed,
+  // there is no effect.
+  SaveDefaultSearchProviderToPrefs(NULL);
+  // Default value for kDefaultSearchProviderEnabled is true.
+  PrefService* prefs = GetPrefs();
+  if (prefs)
+    prefs->SetBoolean(prefs::kDefaultSearchProviderEnabled, true);
+}
+
 bool TemplateURLService::CanReplaceKeywordForHost(
     const std::string& host,
     TemplateURL** to_replace) {
@@ -2497,3 +2460,109 @@
     }
   }
 }
+
+void TemplateURLService::AddTemplateURLsAndSetupDefaultEngine(
+    TemplateURLVector* template_urls,
+    TemplateURL* default_search_provider) {
+  DCHECK(template_urls);
+  is_default_search_managed_ = false;
+  bool database_specified_a_default = (default_search_provider != NULL);
+
+  // Check if default search provider is now managed.
+  scoped_ptr<TemplateURL> default_from_prefs;
+  LoadDefaultSearchProviderFromPrefs(&default_from_prefs,
+                                     &is_default_search_managed_);
+
+  // Remove entries that were created because of policy as they may have
+  // changed since the database was saved.
+  RemoveProvidersCreatedByPolicy(template_urls,
+                                 &default_search_provider,
+                                 default_from_prefs.get());
+
+  PatchMissingSyncGUIDs(template_urls);
+
+  if (is_default_search_managed_) {
+    SetTemplateURLs(*template_urls);
+
+    if (TemplateURLsHaveSamePrefs(default_search_provider,
+                                  default_from_prefs.get())) {
+      // The value from the preferences was previously stored in the database.
+      // Reuse it.
+    } else {
+      // The value from the preferences takes over.
+      default_search_provider = NULL;
+      if (default_from_prefs.get()) {
+        TemplateURLData data(default_from_prefs->data());
+        data.created_by_policy = true;
+        data.id = kInvalidTemplateURLID;
+        default_search_provider = new TemplateURL(profile_, data);
+        if (!AddNoNotify(default_search_provider, true))
+          default_search_provider = NULL;
+      }
+    }
+    // Note that this saves the default search provider to prefs.
+    if (!default_search_provider ||
+        (!default_search_provider->IsExtensionKeyword() &&
+            default_search_provider->SupportsReplacement())) {
+      bool success = SetDefaultSearchProviderNoNotify(default_search_provider);
+      DCHECK(success);
+    }
+  } else {
+    // If we had a managed default, replace it with the synced default if
+    // applicable, or the first provider of the list.
+    TemplateURL* synced_default = GetPendingSyncedDefaultSearchProvider();
+    if (synced_default) {
+      default_search_provider = synced_default;
+      pending_synced_default_search_ = false;
+    } else if (database_specified_a_default &&
+        default_search_provider == NULL) {
+      UMA_HISTOGRAM_ENUMERATION(kFirstPotentialEngineHistogramName,
+                                FIRST_POTENTIAL_CALLSITE_ON_LOAD,
+                                FIRST_POTENTIAL_CALLSITE_MAX);
+      default_search_provider = FirstPotentialDefaultEngine(*template_urls);
+    }
+
+    // If the default search provider existed previously, then just
+    // set the member variable. Otherwise, we'll set it using the method
+    // to ensure that it is saved properly after its id is set.
+    if (default_search_provider &&
+        (default_search_provider->id() != kInvalidTemplateURLID)) {
+      default_search_provider_ = default_search_provider;
+      default_search_provider = NULL;
+    }
+    SetTemplateURLs(*template_urls);
+
+    if (default_search_provider) {
+      // Note that this saves the default search provider to prefs.
+      SetDefaultSearchProvider(default_search_provider);
+    } else {
+      // Always save the default search provider to prefs. That way we don't
+      // have to worry about it being out of sync.
+      if (default_search_provider_)
+        SaveDefaultSearchProviderToPrefs(default_search_provider_);
+    }
+  }
+}
+
+void TemplateURLService::EnsureDefaultSearchProviderExists() {
+  if (!is_default_search_managed_) {
+    bool has_default_search_provider = default_search_provider_ &&
+        default_search_provider_->SupportsReplacement();
+    UMA_HISTOGRAM_BOOLEAN(kHasDSPHistogramName,
+                          has_default_search_provider);
+    // Ensure that default search provider exists. See http://crbug.com/116952.
+    if (!has_default_search_provider) {
+      bool success =
+          SetDefaultSearchProviderNoNotify(FindNewDefaultSearchProvider());
+      DCHECK(success);
+    }
+    // Don't log anything if the user has a NULL default search provider. A
+    // logged value of 0 indicates a custom default search provider.
+    if (default_search_provider_) {
+      UMA_HISTOGRAM_ENUMERATION(
+          kDSPHistogramName,
+          default_search_provider_->prepopulate_id(),
+          TemplateURLPrepopulateData::kMaxPrepopulatedEngineID);
+    }
+  }
+}
diff --git a/chrome/browser/search_engines/template_url_service.h b/chrome/browser/search_engines/template_url_service.h
index adabac7..83826d5 100644
--- a/chrome/browser/search_engines/template_url_service.h
+++ b/chrome/browser/search_engines/template_url_service.h
@@ -225,6 +225,11 @@
   // destroyed at any time so should be used right after the call.
   TemplateURL* FindNewDefaultSearchProvider();
 
+  // Resets the search providers to the prepopulated engines plus any
+  // extension-supplied engines.  Also resets the default search engine unless
+  // it's managed.
+  void ResetNonExtensionURLs();
+
   // Observers used to listen for changes to the model.
   // TemplateURLService does NOT delete the observers when deleted.
   void AddObserver(TemplateURLServiceObserver* observer);
@@ -421,6 +426,9 @@
       scoped_ptr<TemplateURL>* default_provider,
       bool* is_managed);
 
+  // Clears user preferences describing the default search engine.
+  void ClearDefaultProviderFromPrefs();
+
   // Returns true if there is no TemplateURL that has a search url with the
   // specified host, or the only TemplateURLs matching the specified host can
   // be replaced.
@@ -582,6 +590,17 @@
 
   void OnSyncedDefaultSearchProviderGUIDChanged();
 
+  // Adds |template_urls| to |template_urls_| and sets up the default search
+  // provider.  If |default_search_provider| is non-NULL, it must refer to one
+  // of the |template_urls|, and will be used as the new default.
+  void AddTemplateURLsAndSetupDefaultEngine(
+      TemplateURLVector* template_urls,
+      TemplateURL* default_search_provider);
+
+  // If there is no current default search provider, sets the default to the
+  // result of calling FindNewDefaultSearchProvider().
+  void EnsureDefaultSearchProviderExists();
+
   content::NotificationRegistrar notification_registrar_;
   PrefChangeRegistrar pref_change_registrar_;
 
diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc
index 0256bf6..d681c86 100644
--- a/chrome/browser/search_engines/template_url_service_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_unittest.cc
@@ -922,6 +922,83 @@
   AssertEquals(*cloned_url, *model()->GetDefaultSearchProvider());
 }
 
+TEST_F(TemplateURLServiceTest, ResetNonExtensionURLs) {
+  test_util_.VerifyLoad();
+
+  TemplateURL* new_provider = AddKeywordWithDate(
+      "short_name", "keyword", "http://test.com/search?t={searchTerms}",
+      std::string(), std::string(), std::string(),
+      true, "UTF-8", Time(), Time());
+  model()->SetDefaultSearchProvider(new_provider);
+  AddKeywordWithDate(
+      "extension1", "ext_keyword",
+      std::string(extensions::kExtensionScheme) + "://test1", std::string(),
+      std::string(), std::string(), false, "UTF-8", Time(), Time());
+  TemplateURL* default_provider = model()->GetDefaultSearchProvider();
+  EXPECT_NE(SEARCH_ENGINE_GOOGLE,
+      TemplateURLPrepopulateData::GetEngineType(default_provider->url()));
+
+  // Non-extension URLs should go away. Default search engine is Google again.
+  model()->ResetNonExtensionURLs();
+  default_provider = model()->GetDefaultSearchProvider();
+  ASSERT_TRUE(default_provider);
+  EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
+      TemplateURLPrepopulateData::GetEngineType(default_provider->url()));
+  EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext_keyword")));
+  EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
+
+  // Reload URLs. Result should be the same except that extension keywords
+  // aren't persisted.
+  test_util_.ResetModel(true);
+  default_provider = model()->GetDefaultSearchProvider();
+  ASSERT_TRUE(default_provider);
+  EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
+      TemplateURLPrepopulateData::GetEngineType(default_provider->url()));
+  EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext_keyword")));
+  EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
+}
+
+TEST_F(TemplateURLServiceTest, ResetURLsWithManagedDefault) {
+  // Set a managed preference that establishes a default search provider.
+  const char kName[] = "test1";
+  const char kKeyword[] = "test.com";
+  const char kSearchURL[] = "http://test.com/search?t={searchTerms}";
+  const char kIconURL[] = "http://test.com/icon.jpg";
+  const char kEncodings[] = "UTF-16;UTF-32";
+  const char kAlternateURL[] = "http://test.com/search#t={searchTerms}";
+  const char kSearchTermsReplacementKey[] = "espv";
+  test_util_.SetManagedDefaultSearchPreferences(true, kName, kKeyword,
+                                                kSearchURL, std::string(),
+                                                kIconURL, kEncodings,
+                                                kAlternateURL,
+                                                kSearchTermsReplacementKey);
+  test_util_.VerifyLoad();
+  // Verify that the default manager we are getting is the managed one.
+  TemplateURLData data;
+  data.short_name = ASCIIToUTF16(kName);
+  data.SetKeyword(ASCIIToUTF16(kKeyword));
+  data.SetURL(kSearchURL);
+  data.favicon_url = GURL(kIconURL);
+  data.show_in_default_list = true;
+  base::SplitString(kEncodings, ';', &data.input_encodings);
+  data.alternate_urls.push_back(kAlternateURL);
+  data.search_terms_replacement_key = kSearchTermsReplacementKey;
+  Profile* profile = test_util_.profile();
+  scoped_ptr<TemplateURL> expected_managed_default(new TemplateURL(profile,
+                                                                    data));
+  EXPECT_TRUE(model()->is_default_search_managed());
+  const TemplateURL* actual_managed_default =
+      model()->GetDefaultSearchProvider();
+  ExpectSimilar(expected_managed_default.get(), actual_managed_default);
+
+  // The following call has no effect on the managed search engine.
+  model()->ResetNonExtensionURLs();
+
+  EXPECT_TRUE(model()->is_default_search_managed());
+  actual_managed_default = model()->GetDefaultSearchProvider();
+  ExpectSimilar(expected_managed_default.get(), actual_managed_default);
+}
+
 TEST_F(TemplateURLServiceTest, UpdateKeywordSearchTermsForURL) {
   struct TestData {
     const std::string url;
diff --git a/chrome/browser/search_engines/util.cc b/chrome/browser/search_engines/util.cc
index 581f513b..5e7d285 100644
--- a/chrome/browser/search_engines/util.cc
+++ b/chrome/browser/search_engines/util.cc
@@ -149,8 +149,8 @@
   prepopulated_url->last_modified = original_turl->last_modified();
 }
 
-// Loads engines from prepopulate data and merges them in with the existing
-// engines.  This is invoked when the version of the prepopulate data changes.
+// Merges the provided prepopulated engines with the provided existing engines.
+// This is invoked when the version of the prepopulate data changes.
 // If |removed_keyword_guids| is not NULL, the Sync GUID of each item removed
 // from the DB will be added to it.  Note that this function will take
 // ownership of |prepopulated_urls| and will clear the vector.
@@ -262,7 +262,6 @@
   DCHECK_EQ(KEYWORDS_RESULT, result.GetType());
   DCHECK(new_resource_keyword_version);
 
-  *new_resource_keyword_version = 0;
   WDKeywordsResult keyword_result = reinterpret_cast<
       const WDResult<WDKeywordsResult>*>(&result)->GetValue();
 
@@ -288,6 +287,25 @@
         GetTemplateURLByID(*template_urls, default_search_provider_id);
   }
 
+  *new_resource_keyword_version = keyword_result.builtin_keyword_version;
+  GetSearchProvidersUsingLoadedEngines(service, profile, template_urls,
+                                       default_search_provider,
+                                       new_resource_keyword_version,
+                                       removed_keyword_guids);
+}
+
+void GetSearchProvidersUsingLoadedEngines(
+    WebDataService* service,
+    Profile* profile,
+    TemplateURLService::TemplateURLVector* template_urls,
+    TemplateURL** default_search_provider,
+    int* resource_keyword_version,
+    std::set<std::string>* removed_keyword_guids) {
+  DCHECK(service == NULL || BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(template_urls);
+  DCHECK(default_search_provider);
+  DCHECK(resource_keyword_version);
+
   ScopedVector<TemplateURL> prepopulated_urls;
   size_t default_search_index;
   TemplateURLPrepopulateData::GetPrepopulatedEngines(profile,
@@ -296,14 +314,16 @@
                                 *default_search_provider, template_urls,
                                 removed_keyword_guids);
 
-  const int resource_keyword_version =
+  const int prepopulate_resource_keyword_version =
       TemplateURLPrepopulateData::GetDataVersion(
           profile ? profile->GetPrefs() : NULL);
-  if (keyword_result.builtin_keyword_version != resource_keyword_version) {
+  if (*resource_keyword_version < prepopulate_resource_keyword_version) {
     MergeEnginesFromPrepopulateData(profile, service, &prepopulated_urls,
         default_search_index, template_urls, default_search_provider,
         removed_keyword_guids);
-    *new_resource_keyword_version = resource_keyword_version;
+    *resource_keyword_version = prepopulate_resource_keyword_version;
+  } else {
+    *resource_keyword_version = 0;
   }
 }
 
diff --git a/chrome/browser/search_engines/util.h b/chrome/browser/search_engines/util.h
index 432569f3..158841aa 100644
--- a/chrome/browser/search_engines/util.h
+++ b/chrome/browser/search_engines/util.h
@@ -50,6 +50,21 @@
     int* new_resource_keyword_version,
     std::set<std::string>* removed_keyword_guids);
 
+// Like GetSearchProvidersUsingKeywordResult(), but allows the caller to pass in
+// engines in |template_urls| instead of getting them via processing a web data
+// service request.
+// |resource_keyword_version| should contain the version number of the current
+// keyword data, i.e. the version number of the most recent prepopulate data
+// that has been merged into the current keyword data.  On exit, this will be
+// set as in GetSearchProvidersUsingKeywordResult().
+void GetSearchProvidersUsingLoadedEngines(
+    WebDataService* service,
+    Profile* profile,
+    TemplateURLService::TemplateURLVector* template_urls,
+    TemplateURL** default_search_provider,
+    int* resource_keyword_version,
+    std::set<std::string>* removed_keyword_guids);
+
 // Due to a bug, the |input_encodings| field of TemplateURLData could have
 // contained duplicate entries.  This removes those entries and returns whether
 // any were found.