Upload upstream chromium 114.0.5735.31
[platform/framework/web/chromium-efl.git] / components / search_engines / template_url_service.cc
1 // Copyright 2014 The Chromium Authors
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 "components/search_engines/template_url_service.h"
6
7 #include "base/auto_reset.h"
8 #include "base/base64.h"
9 #include "base/base64url.h"
10 #include "base/containers/contains.h"
11 #include "base/debug/crash_logging.h"
12 #include "base/format_macros.h"
13 #include "base/functional/bind.h"
14 #include "base/functional/callback.h"
15 #include "base/functional/callback_helpers.h"
16 #include "base/i18n/case_conversion.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/metrics/field_trial_params.h"
19 #include "base/metrics/histogram_functions.h"
20 #include "base/metrics/histogram_macros.h"
21 #include "base/observer_list.h"
22 #include "base/rand_util.h"
23 #include "base/ranges/algorithm.h"
24 #include "base/strings/string_split.h"
25 #include "base/strings/string_util.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "build/build_config.h"
28 #include "components/pref_registry/pref_registry_syncable.h"
29 #include "components/prefs/pref_service.h"
30 #include "components/search_engines/search_engines_pref_names.h"
31 #include "components/search_engines/search_terms_data.h"
32 #include "components/search_engines/template_url_prepopulate_data.h"
33 #include "components/search_engines/template_url_service_client.h"
34 #include "components/search_engines/template_url_service_observer.h"
35 #include "components/search_engines/template_url_starter_pack_data.h"
36 #include "components/search_engines/util.h"
37 #include "components/sync/model/sync_change.h"
38 #include "components/sync/model/sync_change_processor.h"
39 #include "components/sync/protocol/entity_specifics.pb.h"
40 #include "components/sync/protocol/search_engine_specifics.pb.h"
41 #include "components/url_formatter/url_fixer.h"
42 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
43 #include "url/gurl.h"
44
45 #if BUILDFLAG(IS_ANDROID)
46 #include "components/search_engines/android/template_url_service_android.h"
47 #endif
48
49 typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet;
50 typedef TemplateURLService::SyncDataMap SyncDataMap;
51
52 namespace {
53
54 const char kDeleteSyncedEngineHistogramName[] =
55     "Search.DeleteSyncedSearchEngine";
56 // TODO(yoangela): Consider sharing this const with
57 //  "Omnibox.KeywordModeUsageByEngineType.Accepted" in omnibox_edit_model.cc.
58 const char kKeywordModeUsageByEngineTypeHistogramName[] =
59     "Omnibox.KeywordModeUsageByEngineType";
60
61 // Values for an enumerated histogram used to track whenever an ACTION_DELETE is
62 // sent to the server for search engines. These are persisted. Do not re-number.
63 enum DeleteSyncedSearchEngineEvent {
64   DELETE_ENGINE_USER_ACTION = 0,
65   DELETE_ENGINE_PRE_SYNC = 1,
66   DELETE_ENGINE_EMPTY_FIELD = 2,
67   DELETE_ENGINE_MAX,
68 };
69
70 // Returns true iff the change in |change_list| at index |i| should not be sent
71 // up to the server based on its GUIDs presence in |sync_data| or when compared
72 // to changes after it in |change_list|.
73 // The criteria is:
74 //  1) It is an ACTION_UPDATE or ACTION_DELETE and the sync_guid associated
75 //     with it is NOT found in |sync_data|. We can only update and remove
76 //     entries that were originally from the Sync server.
77 //  2) It is an ACTION_ADD and the sync_guid associated with it is found in
78 //     |sync_data|. We cannot re-add entries that Sync already knew about.
79 //  3) There is an update after an update for the same GUID. We prune earlier
80 //     ones just to save bandwidth (Sync would normally coalesce them).
81 bool ShouldRemoveSyncChange(size_t index,
82                             syncer::SyncChangeList* change_list,
83                             const SyncDataMap* sync_data) {
84   DCHECK(index < change_list->size());
85   const syncer::SyncChange& change_i = (*change_list)[index];
86   const std::string guid = change_i.sync_data().GetSpecifics()
87       .search_engine().sync_guid();
88   syncer::SyncChange::SyncChangeType type = change_i.change_type();
89   if ((type == syncer::SyncChange::ACTION_UPDATE ||
90        type == syncer::SyncChange::ACTION_DELETE) &&
91        sync_data->find(guid) == sync_data->end())
92     return true;
93   if (type == syncer::SyncChange::ACTION_ADD &&
94       sync_data->find(guid) != sync_data->end())
95     return true;
96   if (type == syncer::SyncChange::ACTION_UPDATE) {
97     for (size_t j = index + 1; j < change_list->size(); j++) {
98       const syncer::SyncChange& change_j = (*change_list)[j];
99       if ((syncer::SyncChange::ACTION_UPDATE == change_j.change_type()) &&
100           (change_j.sync_data().GetSpecifics().search_engine().sync_guid() ==
101               guid))
102         return true;
103     }
104   }
105   return false;
106 }
107
108 // Remove SyncChanges that should not be sent to the server from |change_list|.
109 // This is done to eliminate incorrect SyncChanges added by the merge and
110 // conflict resolution logic when it is unsure of whether or not an entry is new
111 // from Sync or originally from the local model. This also removes changes that
112 // would be otherwise be coalesced by Sync in order to save bandwidth.
113 void PruneSyncChanges(const SyncDataMap* sync_data,
114                       syncer::SyncChangeList* change_list) {
115   for (size_t i = 0; i < change_list->size(); ) {
116     if (ShouldRemoveSyncChange(i, change_list, sync_data))
117       change_list->erase(change_list->begin() + i);
118     else
119       ++i;
120   }
121 }
122
123 // Returns true if |turl|'s GUID is not found inside |sync_data|. This is to be
124 // used in MergeDataAndStartSyncing to differentiate between TemplateURLs from
125 // Sync and TemplateURLs that were initially local, assuming |sync_data| is the
126 // |initial_sync_data| parameter.
127 bool IsFromSync(const TemplateURL* turl, const SyncDataMap& sync_data) {
128   return base::Contains(sync_data, turl->sync_guid());
129 }
130
131 // Log the number of instances of a keyword that exist, with zero or more
132 // underscores, which could occur as the result of conflict resolution.
133 void LogDuplicatesHistogram(
134     const TemplateURLService::TemplateURLVector& template_urls) {
135   std::map<std::u16string, int> duplicates;
136   for (auto it = template_urls.begin(); it != template_urls.end(); ++it) {
137     std::u16string keyword = (*it)->keyword();
138     base::TrimString(keyword, u"_", &keyword);
139     duplicates[keyword]++;
140   }
141
142   // Count the keywords with duplicates.
143   int num_dupes = 0;
144   for (std::map<std::u16string, int>::const_iterator it = duplicates.begin();
145        it != duplicates.end(); ++it) {
146     if (it->second > 1)
147       num_dupes++;
148   }
149
150   UMA_HISTOGRAM_COUNTS_100("Search.SearchEngineDuplicateCounts", num_dupes);
151 }
152
153 // Returns the length of the registry portion of a hostname.  For example,
154 // www.google.co.uk will return 5 (the length of co.uk).
155 size_t GetRegistryLength(const std::u16string& host) {
156   return net::registry_controlled_domains::PermissiveGetHostRegistryLength(
157       host, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
158       net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
159 }
160
161 // For keywords that look like hostnames, returns whether KeywordProvider
162 // should require users to type a prefix of the hostname to match against
163 // them, rather than just the domain name portion. In other words, returns
164 // whether the prefix before the domain name should be considered important
165 // for matching purposes. Returns true if the experiment isn't active.
166 bool OmniboxFieldTrialKeywordRequiresRegistry() {
167   // This would normally be
168   // bool OmniboxFieldTrial::KeywordRequiresRegistry()
169   // but that would create a dependency cycle since omnibox depends on
170   // search_engines (and search -> search_engines)
171   constexpr char kBundledExperimentFieldTrialName[] =
172       "OmniboxBundledExperimentV1";
173   constexpr char kKeywordRequiresRegistryRule[] = "KeywordRequiresRegistry";
174   const std::string value = base::GetFieldTrialParamValue(
175       kBundledExperimentFieldTrialName, kKeywordRequiresRegistryRule);
176   return value.empty() || (value == "true");
177 }
178
179 // Returns the length of the important part of the |keyword|, assumed to be
180 // associated with the TemplateURL.  For instance, for the keyword
181 // google.co.uk, this can return 6 (the length of "google").
182 size_t GetMeaningfulKeywordLength(const std::u16string& keyword,
183                                   const TemplateURL* turl) {
184   // Using Omnibox from here is a layer violation and should be fixed.
185   if (OmniboxFieldTrialKeywordRequiresRegistry())
186     return keyword.length();
187   const size_t registry_length = GetRegistryLength(keyword);
188   if (registry_length == std::string::npos)
189     return keyword.length();
190   DCHECK_LT(registry_length, keyword.length());
191   // The meaningful keyword length is the length of any portion before the
192   // registry ("co.uk") and its preceding dot.
193   return keyword.length() - (registry_length ? (registry_length + 1) : 0);
194 }
195
196 bool Contains(TemplateURLService::OwnedTemplateURLVector* template_urls,
197               const TemplateURL* turl) {
198   return FindTemplateURL(template_urls, turl) != template_urls->end();
199 }
200
201 bool IsCreatedByExtension(const TemplateURL* template_url) {
202   return template_url->type() ==
203              TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION ||
204          template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION;
205 }
206
207 }  // namespace
208
209 // TemplateURLService::LessWithPrefix -----------------------------------------
210
211 class TemplateURLService::LessWithPrefix {
212  public:
213   // We want to find the set of keywords that begin with a prefix.  The STL
214   // algorithms will return the set of elements that are "equal to" the
215   // prefix, where "equal(x, y)" means "!(cmp(x, y) || cmp(y, x))".  When
216   // cmp() is the typical std::less<>, this results in lexicographic equality;
217   // we need to extend this to mark a prefix as "not less than" a keyword it
218   // begins, which will cause the desired elements to be considered "equal to"
219   // the prefix.  Note: this is still a strict weak ordering, as required by
220   // equal_range() (though I will not prove that here).
221   //
222   // Unfortunately the calling convention is not "prefix and element" but
223   // rather "two elements", so we pass the prefix as a fake "element" which has
224   // a NULL KeywordDataElement pointer.
225   bool operator()(
226       const KeywordToTURLAndMeaningfulLength::value_type& elem1,
227       const KeywordToTURLAndMeaningfulLength::value_type& elem2) const {
228     return (elem1.second.first == nullptr)
229                ? (elem2.first.compare(0, elem1.first.length(), elem1.first) > 0)
230                : (elem1.first < elem2.first);
231   }
232 };
233
234 // TemplateURLService::Scoper -------------------------------------------------
235
236 class TemplateURLService::Scoper {
237  public:
238   // Keep one of these handles in scope to coalesce all the notifications into a
239   // single notification. Likewise, BatchModeScoper defers web data service
240   // operations into a batch operation.
241   //
242   // Notifications are sent when the last outstanding handle is destroyed and
243   // |model_mutated_notification_pending_| is true.
244   //
245   // The web data service batch operation is performed when the batch mode level
246   // is 0 and more than one operation is pending. This check happens when
247   // BatchModeScoper is destroyed.
248   explicit Scoper(TemplateURLService* service)
249       : batch_mode_scoper_(
250             std::make_unique<KeywordWebDataService::BatchModeScoper>(
251                 service->web_data_service_.get())),
252         service_(service) {
253     ++service_->outstanding_scoper_handles_;
254   }
255
256   Scoper(const Scoper&) = delete;
257   Scoper& operator=(const Scoper&) = delete;
258
259   // When a Scoper is destroyed, the handle count is updated. If the handle
260   // count is at zero, notify the observers that the model has changed if
261   // service is loaded and model was mutated.
262   ~Scoper() {
263     DCHECK_GT(service_->outstanding_scoper_handles_, 0);
264
265     --service_->outstanding_scoper_handles_;
266     if (service_->outstanding_scoper_handles_ == 0 &&
267         service_->model_mutated_notification_pending_) {
268       service_->model_mutated_notification_pending_ = false;
269
270       if (!service_->loaded_)
271         return;
272
273       for (auto& observer : service_->model_observers_)
274         observer.OnTemplateURLServiceChanged();
275     }
276   }
277
278  private:
279   std::unique_ptr<KeywordWebDataService::BatchModeScoper> batch_mode_scoper_;
280   raw_ptr<TemplateURLService> service_;
281 };
282
283 // TemplateURLService ---------------------------------------------------------
284
285 TemplateURLService::TemplateURLService(
286     PrefService* prefs,
287     std::unique_ptr<SearchTermsData> search_terms_data,
288     const scoped_refptr<KeywordWebDataService>& web_data_service,
289     std::unique_ptr<TemplateURLServiceClient> client,
290     const base::RepeatingClosure& dsp_change_callback)
291     : prefs_(prefs),
292       search_terms_data_(std::move(search_terms_data)),
293       web_data_service_(web_data_service),
294       client_(std::move(client)),
295       dsp_change_callback_(dsp_change_callback),
296       default_search_manager_(
297           prefs_,
298           base::BindRepeating(&TemplateURLService::ApplyDefaultSearchChange,
299                               base::Unretained(this))) {
300   DCHECK(search_terms_data_);
301   Init(nullptr, 0);
302 }
303
304 TemplateURLService::TemplateURLService(const Initializer* initializers,
305                                        const int count)
306     : default_search_manager_(
307           prefs_,
308           base::BindRepeating(&TemplateURLService::ApplyDefaultSearchChange,
309                               base::Unretained(this))) {
310   Init(initializers, count);
311 }
312
313 TemplateURLService::~TemplateURLService() {
314   // |web_data_service_| should be deleted during Shutdown().
315   DCHECK(!web_data_service_);
316 }
317
318 // static
319 void TemplateURLService::LogSearchTemplateURLEvent(
320     SearchTemplateURLEvent event) {
321   UMA_HISTOGRAM_ENUMERATION("Search.TemplateURL.Events", event,
322                             SEARCH_TEMPLATE_URL_EVENT_MAX);
323 }
324
325 // static
326 void TemplateURLService::RegisterProfilePrefs(
327     user_prefs::PrefRegistrySyncable* registry) {
328 #if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
329   uint32_t flags = PrefRegistry::NO_REGISTRATION_FLAGS;
330 #else
331   uint32_t flags = user_prefs::PrefRegistrySyncable::SYNCABLE_PREF;
332 #endif
333   registry->RegisterStringPref(prefs::kSyncedDefaultSearchProviderGUID,
334                                std::string(),
335                                flags);
336   registry->RegisterBooleanPref(prefs::kDefaultSearchProviderEnabled, true);
337   registry->RegisterBooleanPref(
338       prefs::kDefaultSearchProviderContextMenuAccessAllowed, true);
339 }
340
341 #if BUILDFLAG(IS_ANDROID)
342 base::android::ScopedJavaLocalRef<jobject> TemplateURLService::GetJavaObject() {
343   if (!template_url_service_android_) {
344     template_url_service_android_ =
345         std::make_unique<TemplateUrlServiceAndroid>(this);
346   }
347   return template_url_service_android_->GetJavaObject();
348 }
349 #endif
350
351 bool TemplateURLService::CanAddAutogeneratedKeyword(
352     const std::u16string& keyword,
353     const GURL& url) {
354   DCHECK(!keyword.empty());  // This should only be called for non-empty
355                              // keywords. If we need to support empty kewords
356                              // the code needs to change slightly.
357   const TemplateURL* existing_url = GetTemplateURLForKeyword(keyword);
358   if (existing_url) {
359     // TODO(tommycli): Currently, this code goes one step beyond
360     // safe_for_autoreplace() and also forbids automatically modifying
361     // prepopulated engines. That's debatable, as we already update prepopulated
362     // provider favicons as the user browses. See UpdateProviderFavicons().
363     return existing_url->safe_for_autoreplace() &&
364            existing_url->prepopulate_id() == 0;
365   }
366
367   // We don't have a TemplateURL with keyword.  We still may not allow this
368   // keyword if there's evidence we may have created this keyword before and
369   // the user renamed it (because, for instance, the keyword is a common word
370   // that may interfere with search queries).  An easy heuristic for this is
371   // whether the user has a TemplateURL that has been manually modified (e.g.,
372   // renamed) connected to the same host.
373   return !url.is_valid() || url.host().empty() ||
374       CanAddAutogeneratedKeywordForHost(url.host());
375 }
376
377 bool TemplateURLService::IsPrepopulatedOrCreatedByPolicy(
378     const TemplateURL* t_url) const {
379   return (t_url->prepopulate_id() > 0 || t_url->created_by_policy() ||
380           t_url->created_from_play_api()) &&
381          t_url->SupportsReplacement(search_terms_data());
382 }
383
384 bool TemplateURLService::ShowInDefaultList(const TemplateURL* t_url) const {
385   return t_url == default_search_provider_ ||
386       IsPrepopulatedOrCreatedByPolicy(t_url);
387 }
388
389 void TemplateURLService::AddMatchingKeywords(
390     const std::u16string& prefix,
391     bool supports_replacement_only,
392     TURLsAndMeaningfulLengths* matches) {
393   AddMatchingKeywordsHelper(
394       keyword_to_turl_and_length_, prefix, supports_replacement_only, matches);
395 }
396
397 TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
398     const std::u16string& keyword) {
399   return const_cast<TemplateURL*>(
400       static_cast<const TemplateURLService*>(this)->
401           GetTemplateURLForKeyword(keyword));
402 }
403
404 const TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
405     const std::u16string& keyword) const {
406   // Finds and returns the best match for |keyword|.
407   const auto match_range = keyword_to_turl_and_length_.equal_range(keyword);
408   if (match_range.first != match_range.second) {
409     // Among the matches for |keyword| in the multimap, return the best one.
410     return std::min_element(
411                match_range.first, match_range.second,
412                [](const auto& a, const auto& b) {
413                  return a.second.first
414                      ->IsBetterThanEngineWithConflictingKeyword(b.second.first);
415                })
416         ->second.first;
417   }
418
419   return (!loaded_ && initial_default_search_provider_ &&
420           (initial_default_search_provider_->keyword() == keyword))
421              ? initial_default_search_provider_.get()
422              : nullptr;
423 }
424
425 TemplateURL* TemplateURLService::GetTemplateURLForGUID(
426     const std::string& sync_guid) {
427 return const_cast<TemplateURL*>(
428       static_cast<const TemplateURLService*>(this)->
429           GetTemplateURLForGUID(sync_guid));
430 }
431
432 const TemplateURL* TemplateURLService::GetTemplateURLForGUID(
433     const std::string& sync_guid) const {
434   auto elem(guid_to_turl_.find(sync_guid));
435   if (elem != guid_to_turl_.end())
436     return elem->second;
437   return (!loaded_ && initial_default_search_provider_ &&
438           (initial_default_search_provider_->sync_guid() == sync_guid))
439              ? initial_default_search_provider_.get()
440              : nullptr;
441 }
442
443 TemplateURL* TemplateURLService::GetTemplateURLForHost(
444     const std::string& host) {
445   return const_cast<TemplateURL*>(
446       static_cast<const TemplateURLService*>(this)->
447           GetTemplateURLForHost(host));
448 }
449
450 const TemplateURL* TemplateURLService::GetTemplateURLForHost(
451     const std::string& host) const {
452   if (loaded_) {
453     // `provider_map_` takes care of finding the best TemplateURL for `host`.
454     return provider_map_->GetTemplateURLForHost(host);
455   }
456   TemplateURL* initial_dsp = initial_default_search_provider_.get();
457   return (initial_dsp &&
458           (initial_dsp->GenerateSearchURL(search_terms_data()).host_piece() ==
459            host))
460              ? initial_dsp
461              : nullptr;
462 }
463
464 size_t TemplateURLService::GetTemplateURLCountForHostForLogging(
465     const std::string& host) const {
466   DCHECK(loaded_);
467   auto* host_urls = provider_map_->GetURLsForHost(host);
468   return host_urls ? host_urls->size() : 0;
469 }
470
471 TemplateURL* TemplateURLService::Add(
472     std::unique_ptr<TemplateURL> template_url) {
473   DCHECK(template_url);
474   DCHECK(
475       !IsCreatedByExtension(template_url.get()) ||
476       (!FindTemplateURLForExtension(template_url->extension_info_->extension_id,
477                                     template_url->type()) &&
478        template_url->id() == kInvalidTemplateURLID));
479
480   return Add(std::move(template_url), true);
481 }
482
483 TemplateURL* TemplateURLService::AddWithOverrides(
484     std::unique_ptr<TemplateURL> template_url,
485     const std::u16string& short_name,
486     const std::u16string& keyword,
487     const std::string& url) {
488   DCHECK(!short_name.empty());
489   DCHECK(!keyword.empty());
490   DCHECK(!url.empty());
491   template_url->data_.SetShortName(short_name);
492   template_url->data_.SetKeyword(keyword);
493   template_url->SetURL(url);
494   return Add(std::move(template_url));
495 }
496
497 void TemplateURLService::Remove(const TemplateURL* template_url) {
498   // CHECK that we aren't trying to Remove() the default search provider.
499   // This has happened before, and causes permanent damage to the user Profile,
500   // which can then be Synced to other installations. It's better to crash
501   // immediately, and that's why this isn't a DCHECK. https://crbug.com/1164024
502   {
503     const TemplateURL* default_provider = GetDefaultSearchProvider();
504
505     // TODO(tommycli): Once we are sure this never happens in practice, we can
506     // remove this CrashKeyString, but we should keep the CHECK.
507     static base::debug::CrashKeyString* crash_key =
508         base::debug::AllocateCrashKeyString("removed_turl_keyword",
509                                             base::debug::CrashKeySize::Size256);
510     base::debug::ScopedCrashKeyString auto_clear(
511         crash_key, base::UTF16ToUTF8(template_url->keyword()));
512
513     CHECK_NE(template_url, default_provider);
514
515     // Before we are loaded, we want to CHECK that we aren't accidentally
516     // removing the in-table representation of the Default Search Engine.
517     //
518     // But users in the wild do indeed have engines with duplicated sync GUIDs.
519     // For instance, Extensions Override Settings API used to have a bug that
520     // would clone GUIDs. So therefore skip the check after loading.
521     // https://crbug.com/1166372#c13
522     if (!loaded() && default_provider &&
523         default_provider->type() !=
524             TemplateURL::Type::NORMAL_CONTROLLED_BY_EXTENSION &&
525         template_url->type() !=
526             TemplateURL::Type::NORMAL_CONTROLLED_BY_EXTENSION) {
527       CHECK_NE(template_url->sync_guid(), default_provider->sync_guid());
528     }
529   }
530
531   auto i = FindTemplateURL(&template_urls_, template_url);
532   if (i == template_urls_.end())
533     return;
534
535   Scoper scoper(this);
536   model_mutated_notification_pending_ = true;
537
538   RemoveFromMaps(template_url);
539
540   // Remove it from the vector containing all TemplateURLs.
541   std::unique_ptr<TemplateURL> scoped_turl = std::move(*i);
542   template_urls_.erase(i);
543
544   if (template_url->type() == TemplateURL::NORMAL) {
545     if (web_data_service_)
546       web_data_service_->RemoveKeyword(template_url->id());
547
548     // Inform sync of the deletion.
549     ProcessTemplateURLChange(FROM_HERE, template_url,
550                              syncer::SyncChange::ACTION_DELETE);
551
552     // The default search engine can't be deleted. But the user defined DSE can
553     // be hidden by an extension or policy and then deleted. Clean up the user
554     // prefs then.
555     if (prefs_ &&
556         (template_url->sync_guid() ==
557          prefs_->GetString(prefs::kSyncedDefaultSearchProviderGUID))) {
558       prefs_->SetString(prefs::kSyncedDefaultSearchProviderGUID, std::string());
559     }
560
561     UMA_HISTOGRAM_ENUMERATION(kDeleteSyncedEngineHistogramName,
562                               DELETE_ENGINE_USER_ACTION, DELETE_ENGINE_MAX);
563   }
564
565   if (loaded_ && client_)
566     client_->DeleteAllSearchTermsForKeyword(template_url->id());
567 }
568
569 void TemplateURLService::RemoveExtensionControlledTURL(
570     const std::string& extension_id,
571     TemplateURL::Type type) {
572   TemplateURL* url = FindTemplateURLForExtension(extension_id, type);
573   if (!url)
574     return;
575   // NULL this out so that we can call Remove.
576   if (default_search_provider_ == url)
577     default_search_provider_ = nullptr;
578   Remove(url);
579 }
580
581 void TemplateURLService::RemoveAutoGeneratedBetween(base::Time created_after,
582                                                     base::Time created_before) {
583   RemoveAutoGeneratedForUrlsBetween(base::NullCallback(), created_after,
584                                     created_before);
585 }
586
587 void TemplateURLService::RemoveAutoGeneratedForUrlsBetween(
588     const base::RepeatingCallback<bool(const GURL&)>& url_filter,
589     base::Time created_after,
590     base::Time created_before) {
591   Scoper scoper(this);
592
593   for (size_t i = 0; i < template_urls_.size();) {
594     TemplateURL* turl = template_urls_[i].get();
595     if (turl->date_created() >= created_after &&
596         (created_before.is_null() || turl->date_created() < created_before) &&
597         turl->safe_for_autoreplace() && turl->prepopulate_id() == 0 &&
598         turl->starter_pack_id() == 0 && !MatchesDefaultSearchProvider(turl) &&
599         (url_filter.is_null() ||
600          url_filter.Run(turl->GenerateSearchURL(search_terms_data())))) {
601       Remove(turl);
602     } else {
603       ++i;
604     }
605   }
606 }
607
608 void TemplateURLService::RegisterOmniboxKeyword(
609     const std::string& extension_id,
610     const std::string& extension_name,
611     const std::string& keyword,
612     const std::string& template_url_string,
613     const base::Time& extension_install_time) {
614   DCHECK(loaded_);
615
616   if (FindTemplateURLForExtension(extension_id,
617                                   TemplateURL::OMNIBOX_API_EXTENSION))
618     return;
619
620   TemplateURLData data;
621   data.SetShortName(base::UTF8ToUTF16(extension_name));
622   data.SetKeyword(base::UTF8ToUTF16(keyword));
623   data.SetURL(template_url_string);
624   Add(std::make_unique<TemplateURL>(data, TemplateURL::OMNIBOX_API_EXTENSION,
625                                     extension_id, extension_install_time,
626                                     false));
627 }
628
629 TemplateURLService::TemplateURLVector TemplateURLService::GetTemplateURLs() {
630   TemplateURLVector result;
631   for (const auto& turl : template_urls_)
632     result.push_back(turl.get());
633   return result;
634 }
635
636 void TemplateURLService::IncrementUsageCount(TemplateURL* url) {
637   DCHECK(url);
638   // Extension-controlled search engines are not persisted.
639   if (url->type() != TemplateURL::NORMAL)
640     return;
641   if (!Contains(&template_urls_, url))
642     return;
643   ++url->data_.usage_count;
644
645   if (web_data_service_)
646     web_data_service_->UpdateKeyword(url->data());
647 }
648
649 void TemplateURLService::ResetTemplateURL(TemplateURL* url,
650                                           const std::u16string& title,
651                                           const std::u16string& keyword,
652                                           const std::string& search_url) {
653   DCHECK(!IsCreatedByExtension(url));
654   DCHECK(!keyword.empty());
655   DCHECK(!search_url.empty());
656   TemplateURLData data(url->data());
657   data.SetShortName(title);
658   data.SetKeyword(keyword);
659   if (search_url != data.url()) {
660     data.SetURL(search_url);
661     // The urls have changed, reset the favicon url.
662     data.favicon_url = GURL();
663   }
664   data.safe_for_autoreplace = false;
665   data.last_modified = clock_->Now();
666   data.is_active = TemplateURLData::ActiveStatus::kTrue;
667
668   Update(url, TemplateURL(data));
669 }
670
671 void TemplateURLService::SetIsActiveTemplateURL(TemplateURL* url,
672                                                 bool is_active) {
673   DCHECK(url);
674
675   TemplateURLData data(url->data());
676   std::string histogram_name = kKeywordModeUsageByEngineTypeHistogramName;
677   if (is_active) {
678     data.is_active = TemplateURLData::ActiveStatus::kTrue;
679     data.safe_for_autoreplace = false;
680     histogram_name.append(".Activated");
681   } else {
682     data.is_active = TemplateURLData::ActiveStatus::kFalse;
683     histogram_name.append(".Deactivated");
684   }
685
686   Update(url, TemplateURL(data));
687
688   base::UmaHistogramEnumeration(
689       histogram_name, url->GetBuiltinEngineType(),
690       BuiltinEngineType::KEYWORD_MODE_ENGINE_TYPE_MAX);
691 }
692
693 TemplateURL* TemplateURLService::CreatePlayAPISearchEngine(
694     const std::u16string& title,
695     const std::u16string& keyword,
696     const std::string& search_url,
697     const std::string& suggestions_url,
698     const std::string& favicon_url) {
699   // It's the caller's responsibility to check that there are no existing
700   // Play API for engine, but still CHECK this to avoid polluting the database.
701   // Currently, we never update Play API engine data. If we ever want to do
702   // that, we need to change how this method behaves.
703   const auto match_range = keyword_to_turl_and_length_.equal_range(keyword);
704   for (auto it = match_range.first; it != match_range.second; ++it) {
705     CHECK(!it->second.first->created_from_play_api());
706   }
707
708   TemplateURLData data;
709   data.SetShortName(title);
710   data.SetKeyword(keyword);
711   data.SetURL(search_url);
712   data.suggestions_url = suggestions_url;
713   data.favicon_url = GURL(favicon_url);
714   data.created_from_play_api = true;
715   // Play API engines are created by explicit user gesture, and should not be
716   // auto-replaceable by an auto-generated engine as the user browses.
717   data.safe_for_autoreplace = false;
718   data.is_active = TemplateURLData::ActiveStatus::kTrue;
719
720   // The Play API search engine is not guaranteed to be the best engine for
721   // |keyword|, if there are user-defined, extension, or policy engines.
722   // In practice on Android, this rarely happens, as there is only policy.
723   return Add(std::make_unique<TemplateURL>(data));
724 }
725
726 void TemplateURLService::UpdateProviderFavicons(
727     const GURL& potential_search_url,
728     const GURL& favicon_url) {
729   DCHECK(loaded_);
730   DCHECK(potential_search_url.is_valid());
731
732   const TemplateURLSet* urls_for_host =
733       provider_map_->GetURLsForHost(potential_search_url.host());
734   if (!urls_for_host)
735     return;
736
737   // Make a copy of the container of the matching TemplateURLs, as the original
738   // container is invalidated as we update the contained TemplateURLs.
739   TemplateURLSet urls_for_host_copy(*urls_for_host);
740
741   Scoper scoper(this);
742   for (TemplateURL* turl : urls_for_host_copy) {
743     if (!IsCreatedByExtension(turl) &&
744         turl->IsSearchURL(potential_search_url, search_terms_data()) &&
745         turl->favicon_url() != favicon_url) {
746       TemplateURLData data(turl->data());
747       data.favicon_url = favicon_url;
748       Update(turl, TemplateURL(data));
749     }
750   }
751 }
752
753 bool TemplateURLService::CanMakeDefault(const TemplateURL* url) const {
754   return (default_search_provider_source_ == DefaultSearchManager::FROM_USER ||
755           default_search_provider_source_ ==
756               DefaultSearchManager::FROM_POLICY_RECOMMENDED ||
757           default_search_provider_source_ ==
758               DefaultSearchManager::FROM_FALLBACK) &&
759          (url != GetDefaultSearchProvider()) &&
760          url->url_ref().SupportsReplacement(search_terms_data()) &&
761          (url->type() == TemplateURL::NORMAL) &&
762          (url->starter_pack_id() != TemplateURLStarterPackData::kTabs);
763 }
764
765 void TemplateURLService::SetUserSelectedDefaultSearchProvider(
766     TemplateURL* url) {
767   // Omnibox keywords cannot be made default. Extension-controlled search
768   // engines can be made default only by the extension itself because they
769   // aren't persisted.
770   DCHECK(!url || !IsCreatedByExtension(url));
771   if (url) {
772     url->data_.is_active = TemplateURLData::ActiveStatus::kTrue;
773   }
774   if (load_failed_) {
775     // Skip the DefaultSearchManager, which will persist to user preferences.
776     if ((default_search_provider_source_ == DefaultSearchManager::FROM_USER) ||
777         (default_search_provider_source_ ==
778          DefaultSearchManager::FROM_FALLBACK)) {
779       ApplyDefaultSearchChange(url ? &url->data() : nullptr,
780                                DefaultSearchManager::FROM_USER);
781     }
782   } else {
783     // We rely on the DefaultSearchManager to call ApplyDefaultSearchChange if,
784     // in fact, the effective DSE changes.
785     if (url) {
786       default_search_manager_.SetUserSelectedDefaultSearchEngine(url->data());
787     } else {
788       default_search_manager_.ClearUserSelectedDefaultSearchEngine();
789     }
790   }
791 }
792
793 const TemplateURL* TemplateURLService::GetDefaultSearchProvider() const {
794   return loaded_ ? default_search_provider_.get()
795                  : initial_default_search_provider_.get();
796 }
797
798 const TemplateURL*
799 TemplateURLService::GetDefaultSearchProviderIgnoringExtensions() const {
800   std::unique_ptr<TemplateURLData> next_search =
801       default_search_manager_.GetDefaultSearchEngineIgnoringExtensions();
802   if (!next_search)
803     return nullptr;
804
805   // Find the TemplateURL matching the data retrieved.
806   auto iter = base::ranges::find_if(
807       template_urls_, [this, &next_search](const auto& turl_to_check) {
808         return TemplateURL::MatchesData(turl_to_check.get(), next_search.get(),
809                                         search_terms_data());
810       });
811   return iter == template_urls_.end() ? nullptr : iter->get();
812 }
813
814 bool TemplateURLService::IsSearchResultsPageFromDefaultSearchProvider(
815     const GURL& url) const {
816   const TemplateURL* default_provider = GetDefaultSearchProvider();
817   return default_provider &&
818       default_provider->IsSearchURL(url, search_terms_data());
819 }
820
821 GURL TemplateURLService::GenerateSearchURLForDefaultSearchProvider(
822     const std::u16string& search_terms) const {
823   const TemplateURL* default_provider = GetDefaultSearchProvider();
824   return default_provider ? default_provider->GenerateSearchURL(
825                                 search_terms_data(), search_terms)
826                           : GURL();
827 }
828
829 absl::optional<TemplateURLService::SearchMetadata>
830 TemplateURLService::ExtractSearchMetadata(const GURL& url) const {
831   const TemplateURL* template_url = GetTemplateURLForHost(url.host());
832   if (!template_url) {
833     return absl::nullopt;
834   }
835
836   GURL normalized_url;
837   std::u16string normalized_search_terms;
838   bool is_valid_search_url =
839       template_url && template_url->KeepSearchTermsInURL(
840                           url, search_terms_data(),
841                           /*keep_search_intent_params=*/true,
842
843                           /*normalize_search_terms=*/true, &normalized_url,
844                           &normalized_search_terms);
845   if (!is_valid_search_url) {
846     return absl::nullopt;
847   }
848
849   return SearchMetadata{template_url, normalized_url, normalized_search_terms};
850 }
851
852 bool TemplateURLService::IsSideSearchSupportedForDefaultSearchProvider() const {
853   const TemplateURL* default_provider = GetDefaultSearchProvider();
854   return default_provider && default_provider->IsSideSearchSupported();
855 }
856
857 bool TemplateURLService::IsSideImageSearchSupportedForDefaultSearchProvider()
858     const {
859   const TemplateURL* default_provider = GetDefaultSearchProvider();
860   return default_provider && default_provider->IsSideImageSearchSupported();
861 }
862
863 GURL TemplateURLService::GenerateSideSearchURLForDefaultSearchProvider(
864     const GURL& search_url,
865     const std::string& version) const {
866   DCHECK(IsSideSearchSupportedForDefaultSearchProvider());
867   return GetDefaultSearchProvider()->GenerateSideSearchURL(search_url, version,
868                                                            search_terms_data());
869 }
870
871 GURL TemplateURLService::RemoveSideSearchParamFromURL(
872     const GURL& search_url) const {
873   if (!IsSideSearchSupportedForDefaultSearchProvider())
874     return search_url;
875   return GetDefaultSearchProvider()->RemoveSideSearchParamFromURL(search_url);
876 }
877
878 GURL TemplateURLService::GenerateSideImageSearchURLForDefaultSearchProvider(
879     const GURL& search_url,
880     const std::string& version) const {
881   DCHECK(IsSideImageSearchSupportedForDefaultSearchProvider());
882   return GetDefaultSearchProvider()->GenerateSideImageSearchURL(search_url,
883                                                                 version);
884 }
885
886 GURL TemplateURLService::RemoveSideImageSearchParamFromURL(
887     const GURL& search_url) const {
888   if (!IsSideImageSearchSupportedForDefaultSearchProvider())
889     return search_url;
890   return GetDefaultSearchProvider()->RemoveSideImageSearchParamFromURL(
891       search_url);
892 }
893
894 bool TemplateURLService::IsExtensionControlledDefaultSearch() const {
895   return default_search_provider_source_ ==
896       DefaultSearchManager::FROM_EXTENSION;
897 }
898
899 void TemplateURLService::RepairPrepopulatedSearchEngines() {
900   // Can't clean DB if it hasn't been loaded.
901   DCHECK(loaded());
902
903   Scoper scoper(this);
904
905   if ((default_search_provider_source_ == DefaultSearchManager::FROM_USER) ||
906       (default_search_provider_source_ ==
907           DefaultSearchManager::FROM_FALLBACK)) {
908     // Clear |default_search_provider_| in case we want to remove the engine it
909     // points to. This will get reset at the end of the function anyway.
910     default_search_provider_ = nullptr;
911   }
912
913   std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
914       TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs_, nullptr);
915   DCHECK(!prepopulated_urls.empty());
916   ActionsFromCurrentData actions(CreateActionsFromCurrentPrepopulateData(
917       &prepopulated_urls, template_urls_, default_search_provider_));
918
919   // Remove items.
920   for (auto i = actions.removed_engines.begin();
921        i < actions.removed_engines.end(); ++i)
922     Remove(*i);
923
924   // Edit items.
925   for (auto i(actions.edited_engines.begin()); i < actions.edited_engines.end();
926        ++i) {
927     TemplateURL new_values(i->second);
928     Update(i->first, new_values);
929   }
930
931   // Add items.
932   for (std::vector<TemplateURLData>::const_iterator i =
933            actions.added_engines.begin();
934        i < actions.added_engines.end();
935        ++i) {
936     Add(std::make_unique<TemplateURL>(*i));
937   }
938
939   base::AutoReset<DefaultSearchChangeOrigin> change_origin(
940       &dsp_change_origin_, DSP_CHANGE_PROFILE_RESET);
941
942   default_search_manager_.ClearUserSelectedDefaultSearchEngine();
943
944   if (default_search_provider_) {
945     // Set fallback engine as user selected, because repair is considered a user
946     // action and we are expected to sync new fallback engine to other devices.
947     const TemplateURLData* fallback_engine_data =
948         default_search_manager_.GetFallbackSearchEngine();
949     if (fallback_engine_data) {
950       TemplateURL* fallback_engine =
951           FindPrepopulatedTemplateURL(fallback_engine_data->prepopulate_id);
952       // The fallback engine is created from built-in/override data that should
953       // always have a prepopulate ID, so this engine should always exist after
954       // a repair.
955       DCHECK(fallback_engine);
956       // Write the fallback engine's GUID to prefs, which will cause
957       // OnSyncedDefaultSearchProviderGUIDChanged() to set it as the new
958       // user-selected engine.
959       prefs_->SetString(prefs::kSyncedDefaultSearchProviderGUID,
960                         fallback_engine->sync_guid());
961     }
962   } else {
963     // If the default search provider came from a user pref we would have been
964     // notified of the new (fallback-provided) value in
965     // ClearUserSelectedDefaultSearchEngine() above. Since we are here, the
966     // value was presumably originally a fallback value (which may have been
967     // repaired).
968     DefaultSearchManager::Source source;
969     const TemplateURLData* new_dse =
970         default_search_manager_.GetDefaultSearchEngine(&source);
971     ApplyDefaultSearchChange(new_dse, source);
972   }
973 }
974
975 void TemplateURLService::RepairStarterPackEngines() {
976   DCHECK(loaded());
977
978   Scoper scoper(this);
979
980   std::vector<std::unique_ptr<TemplateURLData>> starter_pack_engines =
981       TemplateURLStarterPackData::GetStarterPackEngines();
982   DCHECK(!starter_pack_engines.empty());
983   ActionsFromCurrentData actions(CreateActionsFromCurrentStarterPackData(
984       &starter_pack_engines, template_urls_));
985
986   // Remove items.
987   for (auto i = actions.removed_engines.begin();
988        i < actions.removed_engines.end(); ++i) {
989     Remove(*i);
990   }
991
992   // Edit items.
993   for (auto i(actions.edited_engines.begin()); i < actions.edited_engines.end();
994        ++i) {
995     Update(i->first, TemplateURL(i->second));
996   }
997
998   // Add items.
999   for (std::vector<TemplateURLData>::const_iterator i =
1000            actions.added_engines.begin();
1001        i < actions.added_engines.end(); ++i) {
1002     Add(std::make_unique<TemplateURL>(*i));
1003   }
1004 }
1005
1006 void TemplateURLService::AddObserver(TemplateURLServiceObserver* observer) {
1007   model_observers_.AddObserver(observer);
1008 }
1009
1010 void TemplateURLService::RemoveObserver(TemplateURLServiceObserver* observer) {
1011   model_observers_.RemoveObserver(observer);
1012 }
1013
1014 void TemplateURLService::Load() {
1015   if (loaded_ || load_handle_ || disable_load_)
1016     return;
1017
1018   if (web_data_service_)
1019     load_handle_ = web_data_service_->GetKeywords(this);
1020   else
1021     ChangeToLoadedState();
1022 }
1023
1024 base::CallbackListSubscription TemplateURLService::RegisterOnLoadedCallback(
1025     base::OnceClosure callback) {
1026   return loaded_ ? base::CallbackListSubscription()
1027                  : on_loaded_callbacks_.Add(std::move(callback));
1028 }
1029
1030 void TemplateURLService::EmitTemplateURLActiveOnStartupHistogram(
1031     OwnedTemplateURLVector* template_urls) {
1032   DCHECK(template_urls);
1033
1034   for (auto& turl : *template_urls) {
1035     std::string histogram_name = kKeywordModeUsageByEngineTypeHistogramName;
1036     histogram_name.append(
1037         (turl->is_active() == TemplateURLData::ActiveStatus::kTrue)
1038             ? ".ActiveOnStartup"
1039             : ".InactiveOnStartup");
1040     base::UmaHistogramEnumeration(
1041         histogram_name, turl->GetBuiltinEngineType(),
1042         BuiltinEngineType::KEYWORD_MODE_ENGINE_TYPE_MAX);
1043   }
1044 }
1045
1046 void TemplateURLService::OnWebDataServiceRequestDone(
1047     KeywordWebDataService::Handle h,
1048     std::unique_ptr<WDTypedResult> result) {
1049   // Reset the load_handle so that we don't try and cancel the load in
1050   // the destructor.
1051   load_handle_ = 0;
1052
1053   if (!result) {
1054     // Results are null if the database went away or (most likely) wasn't
1055     // loaded.
1056     load_failed_ = true;
1057     web_data_service_ = nullptr;
1058     ChangeToLoadedState();
1059     return;
1060   }
1061
1062   std::unique_ptr<OwnedTemplateURLVector> template_urls =
1063       std::make_unique<OwnedTemplateURLVector>();
1064   int new_resource_keyword_version = 0;
1065   int new_resource_starter_pack_version = 0;
1066   {
1067     GetSearchProvidersUsingKeywordResult(
1068         *result, web_data_service_.get(), prefs_, template_urls.get(),
1069         (default_search_provider_source_ == DefaultSearchManager::FROM_USER)
1070             ? initial_default_search_provider_.get()
1071             : nullptr,
1072         search_terms_data(), &new_resource_keyword_version,
1073         &new_resource_starter_pack_version, &pre_sync_deletes_);
1074   }
1075
1076   Scoper scoper(this);
1077
1078   {
1079     PatchMissingSyncGUIDs(template_urls.get());
1080     MaybeSetIsActiveSearchEngines(template_urls.get());
1081     EmitTemplateURLActiveOnStartupHistogram(template_urls.get());
1082     SetTemplateURLs(std::move(template_urls));
1083
1084     // This initializes provider_map_ which should be done before
1085     // calling UpdateKeywordSearchTermsForURL.
1086     ChangeToLoadedState();
1087
1088     // Index any visits that occurred before we finished loading.
1089     for (size_t i = 0; i < visits_to_add_.size(); ++i)
1090       UpdateKeywordSearchTermsForURL(visits_to_add_[i]);
1091     visits_to_add_.clear();
1092
1093     if (new_resource_keyword_version)
1094       web_data_service_->SetBuiltinKeywordVersion(new_resource_keyword_version);
1095
1096     if (new_resource_starter_pack_version)
1097       web_data_service_->SetStarterPackKeywordVersion(
1098           new_resource_starter_pack_version);
1099   }
1100
1101   if (default_search_provider_) {
1102     base::UmaHistogramEnumeration(
1103         "Search.DefaultSearchProviderType2",
1104         default_search_provider_->GetEngineType(search_terms_data()),
1105         SEARCH_ENGINE_MAX);
1106   }
1107 }
1108
1109 std::u16string TemplateURLService::GetKeywordShortName(
1110     const std::u16string& keyword,
1111     bool* is_omnibox_api_extension_keyword) const {
1112   const TemplateURL* template_url = GetTemplateURLForKeyword(keyword);
1113
1114   // TODO(sky): Once LocationBarView adds a listener to the TemplateURLService
1115   // to track changes to the model, this should become a DCHECK.
1116   if (template_url) {
1117     *is_omnibox_api_extension_keyword =
1118         template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION;
1119     return template_url->AdjustedShortNameForLocaleDirection();
1120   }
1121   *is_omnibox_api_extension_keyword = false;
1122   return std::u16string();
1123 }
1124
1125 void TemplateURLService::OnHistoryURLVisited(const URLVisitedDetails& details) {
1126   if (!loaded_)
1127     visits_to_add_.push_back(details);
1128   else
1129     UpdateKeywordSearchTermsForURL(details);
1130 }
1131
1132 void TemplateURLService::Shutdown() {
1133   for (auto& observer : model_observers_)
1134     observer.OnTemplateURLServiceShuttingDown();
1135
1136   if (client_)
1137     client_->Shutdown();
1138   // This check has to be done at Shutdown() instead of in the dtor to ensure
1139   // that no clients of KeywordWebDataService are holding ptrs to it after the
1140   // first phase of the KeyedService Shutdown() process.
1141   if (load_handle_) {
1142     DCHECK(web_data_service_);
1143     web_data_service_->CancelRequest(load_handle_);
1144   }
1145   web_data_service_ = nullptr;
1146 }
1147
1148 void TemplateURLService::WaitUntilReadyToSync(base::OnceClosure done) {
1149   DCHECK(!on_loaded_callback_for_sync_);
1150
1151   // We force a load here to allow remote updates to be processed, without
1152   // waiting for the lazy load.
1153   Load();
1154
1155   if (loaded_)
1156     std::move(done).Run();
1157   else
1158     on_loaded_callback_for_sync_ = std::move(done);
1159 }
1160
1161 syncer::SyncDataList TemplateURLService::GetAllSyncData(
1162     syncer::ModelType type) const {
1163   DCHECK_EQ(syncer::SEARCH_ENGINES, type);
1164
1165   syncer::SyncDataList current_data;
1166   for (const auto& turl : template_urls_) {
1167     // We don't sync keywords managed by policy.
1168     if (turl->created_by_policy())
1169       continue;
1170     // We don't sync extension-controlled search engines.
1171     if (turl->type() != TemplateURL::NORMAL)
1172       continue;
1173     current_data.push_back(CreateSyncDataFromTemplateURL(*turl));
1174   }
1175
1176   return current_data;
1177 }
1178
1179 absl::optional<syncer::ModelError> TemplateURLService::ProcessSyncChanges(
1180     const base::Location& from_here,
1181     const syncer::SyncChangeList& change_list) {
1182   if (!models_associated_) {
1183     return syncer::ModelError(FROM_HERE, "Models not yet associated.");
1184   }
1185   DCHECK(loaded_);
1186
1187   base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
1188
1189   Scoper scoper(this);
1190
1191   // We've started syncing, so set our origin member to the base Sync value.
1192   // As we move through Sync Code, we may set this to increasingly specific
1193   // origins so we can tell what exactly caused a DSP change.
1194   base::AutoReset<DefaultSearchChangeOrigin> change_origin_unintentional(
1195       &dsp_change_origin_, DSP_CHANGE_SYNC_UNINTENTIONAL);
1196
1197   syncer::SyncChangeList new_changes;
1198   absl::optional<syncer::ModelError> error;
1199   for (auto iter = change_list.begin(); iter != change_list.end(); ++iter) {
1200     DCHECK_EQ(syncer::SEARCH_ENGINES, iter->sync_data().GetDataType());
1201
1202     TemplateURL* existing_turl = GetTemplateURLForGUID(
1203         iter->sync_data().GetSpecifics().search_engine().sync_guid());
1204     std::unique_ptr<TemplateURL> turl =
1205         CreateTemplateURLFromTemplateURLAndSyncData(
1206             client_.get(), prefs_, search_terms_data(), existing_turl,
1207             iter->sync_data(), &new_changes);
1208     if (!turl)
1209       continue;
1210
1211     const std::string error_msg =
1212         "ProcessSyncChanges failed on ChangeType " +
1213         syncer::SyncChange::ChangeTypeToString(iter->change_type());
1214     if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) {
1215       if (!existing_turl) {
1216         // Can't DELETE a non-existent engine, although we log it.
1217         LogSearchTemplateURLEvent(SYNC_DELETE_FAIL_NONEXISTENT_ENGINE);
1218         error = syncer::ModelError(FROM_HERE, error_msg);
1219         continue;
1220       }
1221
1222       // We can get an ACTION_DELETE for the default search provider if the user
1223       // has changed the default search provider on a different machine, and we
1224       // get the search engine update before the preference update.
1225       //
1226       // In this case, ignore the delete, because we never want to reset the
1227       // default search provider as a result of ACTION_DELETE. If the preference
1228       // update arrives later, we may be stuck with an extra search engine entry
1229       // in this edge case, but it's better than most alternatives.
1230       //
1231       // In the past, we tried re-creating the deleted TemplateURL, but it was
1232       // likely a source of duplicate search engine entries. crbug.com/1022775
1233       if (existing_turl != GetDefaultSearchProvider()) {
1234         Remove(existing_turl);
1235         LogSearchTemplateURLEvent(SYNC_DELETE_SUCCESS);
1236       } else {
1237         LogSearchTemplateURLEvent(SYNC_DELETE_FAIL_DEFAULT_SEARCH_PROVIDER);
1238       }
1239       continue;
1240     }
1241
1242     // Because TemplateURLService sometimes ignores remote Sync changes which
1243     // we cannot cleanly apply, we need to handle ADD and UPDATE together.
1244     // Ignore what the other Sync layers THINK the change type is. Instead:
1245     // If we have an existing engine, treat as an update.
1246     DCHECK(iter->change_type() == syncer::SyncChange::ACTION_ADD ||
1247            iter->change_type() == syncer::SyncChange::ACTION_UPDATE);
1248
1249     if (!existing_turl) {
1250       if (iter->change_type() == syncer::SyncChange::ACTION_UPDATE) {
1251         // This can happen if we have silently deleted a replaceable engine due
1252         // to keyword conflict, and Sync server sends us an UPDATE to it.
1253         LogSearchTemplateURLEvent(SYNC_UPDATE_CONVERTED_TO_ADD);
1254       }
1255
1256       base::AutoReset<DefaultSearchChangeOrigin> change_origin_add(
1257           &dsp_change_origin_, DSP_CHANGE_SYNC_ADD);
1258       // Force the local ID to kInvalidTemplateURLID so we can add it.
1259       TemplateURLData data(turl->data());
1260       data.id = kInvalidTemplateURLID;
1261
1262       TemplateURL* added = Add(std::make_unique<TemplateURL>(data));
1263       if (added) {
1264         MaybeUpdateDSEViaPrefs(added);
1265
1266         LogSearchTemplateURLEvent(SYNC_ADD_SUCCESS);
1267       } else {
1268         // Currently, in practice, this means that we tried to add a replaceable
1269         // duplicate that was worse than our existing entry, but the API doesn't
1270         // promise that, so we just log a generic SYNC_ADD_FAIL_OTHER_ERROR.
1271         LogSearchTemplateURLEvent(SYNC_ADD_FAIL_OTHER_ERROR);
1272       }
1273     } else {
1274       if (iter->change_type() == syncer::SyncChange::ACTION_ADD) {
1275         // This can happen if we have ignored a DELETE request in the past to
1276         // avoid deleting the default search provider, and later on, Sync tries
1277         // to re-ADD something it thinks it has deleted.
1278         LogSearchTemplateURLEvent(SYNC_ADD_CONVERTED_TO_UPDATE);
1279       }
1280
1281       // Since we've already found |existing_turl| by GUID, this Update() should
1282       // always return true, but we still don't want to crash if it fails.
1283       DCHECK(existing_turl);
1284       bool update_success = Update(existing_turl, *turl);
1285       DCHECK(update_success);
1286
1287       MaybeUpdateDSEViaPrefs(existing_turl);
1288       LogSearchTemplateURLEvent(SYNC_UPDATE_SUCCESS);
1289     }
1290   }
1291
1292   // If something went wrong, we want to prematurely exit to avoid pushing
1293   // inconsistent data to Sync. We return the last error we received.
1294   if (error) {
1295     return error;
1296   }
1297
1298   return sync_processor_->ProcessSyncChanges(from_here, new_changes);
1299 }
1300
1301 absl::optional<syncer::ModelError> TemplateURLService::MergeDataAndStartSyncing(
1302     syncer::ModelType type,
1303     const syncer::SyncDataList& initial_sync_data,
1304     std::unique_ptr<syncer::SyncChangeProcessor> sync_processor) {
1305   DCHECK(loaded_);
1306   DCHECK_EQ(type, syncer::SEARCH_ENGINES);
1307   DCHECK(!sync_processor_);
1308   DCHECK(sync_processor);
1309
1310   // Disable sync if we failed to load.
1311   if (load_failed_) {
1312     return syncer::ModelError(FROM_HERE, "Local database load failed.");
1313   }
1314
1315   sync_processor_ = std::move(sync_processor);
1316
1317   // We do a lot of calls to Add/Remove/ResetTemplateURL here, so ensure we
1318   // don't step on our own toes.
1319   base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
1320
1321   Scoper scoper(this);
1322
1323   // We've started syncing, so set our origin member to the base Sync value.
1324   // As we move through Sync Code, we may set this to increasingly specific
1325   // origins so we can tell what exactly caused a DSP change.
1326   base::AutoReset<DefaultSearchChangeOrigin> change_origin(&dsp_change_origin_,
1327       DSP_CHANGE_SYNC_UNINTENTIONAL);
1328
1329   syncer::SyncChangeList new_changes;
1330
1331   // Build maps of our sync GUIDs to syncer::SyncData.
1332   SyncDataMap local_data_map = CreateGUIDToSyncDataMap(
1333       GetAllSyncData(syncer::SEARCH_ENGINES));
1334   SyncDataMap sync_data_map = CreateGUIDToSyncDataMap(initial_sync_data);
1335
1336   for (SyncDataMap::const_iterator iter = sync_data_map.begin();
1337       iter != sync_data_map.end(); ++iter) {
1338     TemplateURL* local_turl = GetTemplateURLForGUID(iter->first);
1339     std::unique_ptr<TemplateURL> sync_turl(
1340         CreateTemplateURLFromTemplateURLAndSyncData(
1341             client_.get(), prefs_, search_terms_data(), local_turl,
1342             iter->second, &new_changes));
1343     if (!sync_turl)
1344       continue;
1345
1346     if (pre_sync_deletes_.find(sync_turl->sync_guid()) !=
1347         pre_sync_deletes_.end()) {
1348       // This entry was deleted before the initial sync began (possibly through
1349       // preprocessing in TemplateURLService's loading code). Ignore it and send
1350       // an ACTION_DELETE up to the server.
1351       new_changes.push_back(
1352           syncer::SyncChange(FROM_HERE,
1353                              syncer::SyncChange::ACTION_DELETE,
1354                              iter->second));
1355       UMA_HISTOGRAM_ENUMERATION(kDeleteSyncedEngineHistogramName,
1356           DELETE_ENGINE_PRE_SYNC, DELETE_ENGINE_MAX);
1357       continue;
1358     }
1359
1360     if (local_turl) {
1361       DCHECK(IsFromSync(local_turl, sync_data_map));
1362       // This local search engine is already synced. If the timestamp differs
1363       // from Sync, we need to update locally or to the cloud. Note that if the
1364       // timestamps are equal, we touch neither.
1365       if (sync_turl->last_modified() > local_turl->last_modified()) {
1366         // We've received an update from Sync. We should replace all synced
1367         // fields in the local TemplateURL. Note that this includes the
1368         // TemplateURLID and the TemplateURL may have to be reparsed. This
1369         // also makes the local data's last_modified timestamp equal to Sync's,
1370         // avoiding an Update on the next MergeData call.
1371         Update(local_turl, *sync_turl);
1372       } else if (sync_turl->last_modified() < local_turl->last_modified()) {
1373         // Otherwise, we know we have newer data, so update Sync with our
1374         // data fields.
1375         new_changes.push_back(
1376             syncer::SyncChange(FROM_HERE,
1377                                syncer::SyncChange::ACTION_UPDATE,
1378                                local_data_map[local_turl->sync_guid()]));
1379       }
1380       local_data_map.erase(iter->first);
1381     } else {
1382       // The search engine from the cloud has not been synced locally. Merge it
1383       // into our local model. This will handle any conflicts with local (and
1384       // already-synced) TemplateURLs. It will prefer to keep entries from Sync
1385       // over not-yet-synced TemplateURLs.
1386       MergeInSyncTemplateURL(sync_turl.get(), sync_data_map, &new_changes,
1387                              &local_data_map);
1388     }
1389   }
1390
1391
1392   // The remaining SyncData in local_data_map should be everything that needs to
1393   // be pushed as ADDs to sync.
1394   for (SyncDataMap::const_iterator iter = local_data_map.begin();
1395       iter != local_data_map.end(); ++iter) {
1396     new_changes.push_back(
1397         syncer::SyncChange(FROM_HERE,
1398                            syncer::SyncChange::ACTION_ADD,
1399                            iter->second));
1400   }
1401
1402   // Do some post-processing on the change list to ensure that we are sending
1403   // valid changes to sync_processor_.
1404   PruneSyncChanges(&sync_data_map, &new_changes);
1405
1406   LogDuplicatesHistogram(GetTemplateURLs());
1407   absl::optional<syncer::ModelError> error =
1408       sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
1409   if (!error.has_value()) {
1410     // The ACTION_DELETEs from this set are processed. Empty it so we don't try
1411     // to reuse them on the next call to MergeDataAndStartSyncing.
1412     pre_sync_deletes_.clear();
1413
1414     models_associated_ = true;
1415   }
1416
1417   return error;
1418 }
1419
1420 void TemplateURLService::StopSyncing(syncer::ModelType type) {
1421   DCHECK_EQ(type, syncer::SEARCH_ENGINES);
1422   models_associated_ = false;
1423   sync_processor_.reset();
1424 }
1425
1426 void TemplateURLService::ProcessTemplateURLChange(
1427     const base::Location& from_here,
1428     const TemplateURL* turl,
1429     syncer::SyncChange::SyncChangeType type) {
1430   DCHECK(turl);
1431
1432   if (!models_associated_)
1433     return;  // Not syncing.
1434
1435   if (processing_syncer_changes_)
1436     return;  // These are changes originating from us. Ignore.
1437
1438   // Avoid syncing keywords managed by policy.
1439   if (turl->created_by_policy())
1440     return;
1441
1442   // Avoid syncing extension-controlled search engines.
1443   if (turl->type() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION)
1444     return;
1445
1446   syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*turl);
1447   syncer::SyncChangeList changes = {
1448       syncer::SyncChange(from_here, type, sync_data)};
1449   sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
1450 }
1451
1452 std::string TemplateURLService::GetSessionToken() {
1453   base::TimeTicks current_time(base::TimeTicks::Now());
1454   // Renew token if it expired.
1455   if (current_time > token_expiration_time_) {
1456     const size_t kTokenBytes = 12;
1457     std::string raw_data;
1458     base::RandBytes(base::WriteInto(&raw_data, kTokenBytes + 1), kTokenBytes);
1459     base::Base64UrlEncode(raw_data,
1460                           base::Base64UrlEncodePolicy::INCLUDE_PADDING,
1461                           &current_token_);
1462   }
1463
1464   // Extend expiration time another 60 seconds.
1465   token_expiration_time_ = current_time + base::Seconds(60);
1466   return current_token_;
1467 }
1468
1469 void TemplateURLService::ClearSessionToken() {
1470   token_expiration_time_ = base::TimeTicks();
1471 }
1472
1473 // static
1474 TemplateURLData::ActiveStatus TemplateURLService::ActiveStatusFromSync(
1475     sync_pb::SearchEngineSpecifics_ActiveStatus is_active) {
1476   switch (is_active) {
1477     case sync_pb::SearchEngineSpecifics_ActiveStatus::
1478         SearchEngineSpecifics_ActiveStatus_ACTIVE_STATUS_UNSPECIFIED:
1479       return TemplateURLData::ActiveStatus::kUnspecified;
1480     case sync_pb::SearchEngineSpecifics_ActiveStatus::
1481         SearchEngineSpecifics_ActiveStatus_ACTIVE_STATUS_TRUE:
1482       return TemplateURLData::ActiveStatus::kTrue;
1483     case sync_pb::SearchEngineSpecifics_ActiveStatus::
1484         SearchEngineSpecifics_ActiveStatus_ACTIVE_STATUS_FALSE:
1485       return TemplateURLData::ActiveStatus::kFalse;
1486   }
1487 }
1488
1489 // static
1490 sync_pb::SearchEngineSpecifics_ActiveStatus
1491 TemplateURLService::ActiveStatusToSync(
1492     TemplateURLData::ActiveStatus is_active) {
1493   switch (is_active) {
1494     case TemplateURLData::ActiveStatus::kUnspecified:
1495       return sync_pb::SearchEngineSpecifics_ActiveStatus::
1496           SearchEngineSpecifics_ActiveStatus_ACTIVE_STATUS_UNSPECIFIED;
1497     case TemplateURLData::ActiveStatus::kTrue:
1498       return sync_pb::SearchEngineSpecifics_ActiveStatus::
1499           SearchEngineSpecifics_ActiveStatus_ACTIVE_STATUS_TRUE;
1500     case TemplateURLData::ActiveStatus::kFalse:
1501       return sync_pb::SearchEngineSpecifics_ActiveStatus::
1502           SearchEngineSpecifics_ActiveStatus_ACTIVE_STATUS_FALSE;
1503   }
1504 }
1505
1506 // static
1507 syncer::SyncData TemplateURLService::CreateSyncDataFromTemplateURL(
1508     const TemplateURL& turl) {
1509   sync_pb::EntitySpecifics specifics;
1510   sync_pb::SearchEngineSpecifics* se_specifics =
1511       specifics.mutable_search_engine();
1512   se_specifics->set_short_name(base::UTF16ToUTF8(turl.short_name()));
1513   se_specifics->set_keyword(base::UTF16ToUTF8(turl.keyword()));
1514   se_specifics->set_favicon_url(turl.favicon_url().spec());
1515   se_specifics->set_url(turl.url());
1516   se_specifics->set_safe_for_autoreplace(turl.safe_for_autoreplace());
1517   se_specifics->set_originating_url(turl.originating_url().spec());
1518   se_specifics->set_date_created(turl.date_created().ToInternalValue());
1519   se_specifics->set_input_encodings(
1520       base::JoinString(turl.input_encodings(), ";"));
1521   se_specifics->set_suggestions_url(turl.suggestions_url());
1522   se_specifics->set_prepopulate_id(turl.prepopulate_id());
1523   if (!turl.image_url().empty())
1524     se_specifics->set_image_url(turl.image_url());
1525   se_specifics->set_new_tab_url(turl.new_tab_url());
1526   if (!turl.search_url_post_params().empty())
1527     se_specifics->set_search_url_post_params(turl.search_url_post_params());
1528   if (!turl.suggestions_url_post_params().empty()) {
1529     se_specifics->set_suggestions_url_post_params(
1530         turl.suggestions_url_post_params());
1531   }
1532   if (!turl.image_url_post_params().empty())
1533     se_specifics->set_image_url_post_params(turl.image_url_post_params());
1534   se_specifics->set_last_modified(turl.last_modified().ToInternalValue());
1535   se_specifics->set_sync_guid(turl.sync_guid());
1536   for (size_t i = 0; i < turl.alternate_urls().size(); ++i)
1537     se_specifics->add_alternate_urls(turl.alternate_urls()[i]);
1538   se_specifics->set_is_active(ActiveStatusToSync(turl.is_active()));
1539   se_specifics->set_starter_pack_id(turl.starter_pack_id());
1540
1541   return syncer::SyncData::CreateLocalData(se_specifics->sync_guid(),
1542                                            se_specifics->keyword(),
1543                                            specifics);
1544 }
1545
1546 // static
1547 std::unique_ptr<TemplateURL>
1548 TemplateURLService::CreateTemplateURLFromTemplateURLAndSyncData(
1549     TemplateURLServiceClient* client,
1550     PrefService* prefs,
1551     const SearchTermsData& search_terms_data,
1552     const TemplateURL* existing_turl,
1553     const syncer::SyncData& sync_data,
1554     syncer::SyncChangeList* change_list) {
1555   DCHECK(change_list);
1556
1557   sync_pb::SearchEngineSpecifics specifics =
1558       sync_data.GetSpecifics().search_engine();
1559
1560   // Past bugs might have caused either of these fields to be empty.  Just
1561   // delete this data off the server.
1562   if (specifics.url().empty() || specifics.sync_guid().empty()) {
1563     change_list->push_back(
1564         syncer::SyncChange(FROM_HERE,
1565                            syncer::SyncChange::ACTION_DELETE,
1566                            sync_data));
1567     UMA_HISTOGRAM_ENUMERATION(kDeleteSyncedEngineHistogramName,
1568         DELETE_ENGINE_EMPTY_FIELD, DELETE_ENGINE_MAX);
1569     return nullptr;
1570   }
1571
1572   TemplateURLData data(existing_turl ?
1573       existing_turl->data() : TemplateURLData());
1574   data.SetShortName(base::UTF8ToUTF16(specifics.short_name()));
1575   data.originating_url = GURL(specifics.originating_url());
1576   std::u16string keyword(base::UTF8ToUTF16(specifics.keyword()));
1577   // NOTE: Once this code has shipped in a couple of stable releases, we can
1578   // probably remove the migration portion, comment out the
1579   // "autogenerate_keyword" field entirely in the .proto file, and fold the
1580   // empty keyword case into the "delete data" block above.
1581   bool reset_keyword =
1582       specifics.autogenerate_keyword() || specifics.keyword().empty();
1583   if (reset_keyword)
1584     keyword = u"dummy";  // Will be replaced below.
1585   DCHECK(!keyword.empty());
1586   data.SetKeyword(keyword);
1587   data.SetURL(specifics.url());
1588   data.suggestions_url = specifics.suggestions_url();
1589   data.image_url = specifics.image_url();
1590   data.new_tab_url = specifics.new_tab_url();
1591   data.search_url_post_params = specifics.search_url_post_params();
1592   data.suggestions_url_post_params = specifics.suggestions_url_post_params();
1593   data.image_url_post_params = specifics.image_url_post_params();
1594   data.favicon_url = GURL(specifics.favicon_url());
1595   data.safe_for_autoreplace = specifics.safe_for_autoreplace();
1596   data.input_encodings = base::SplitString(
1597       specifics.input_encodings(), ";",
1598       base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
1599   // If the server data has duplicate encodings, we'll want to push an update
1600   // below to correct it.  Note that we also fix this in
1601   // GetSearchProvidersUsingKeywordResult(), since otherwise we'd never correct
1602   // local problems for clients which have disabled search engine sync.
1603   bool deduped = DeDupeEncodings(&data.input_encodings);
1604   data.date_created = base::Time::FromInternalValue(specifics.date_created());
1605   data.last_modified = base::Time::FromInternalValue(specifics.last_modified());
1606   data.prepopulate_id = specifics.prepopulate_id();
1607   data.sync_guid = specifics.sync_guid();
1608   data.alternate_urls.clear();
1609   for (int i = 0; i < specifics.alternate_urls_size(); ++i)
1610     data.alternate_urls.push_back(specifics.alternate_urls(i));
1611   data.is_active = ActiveStatusFromSync(specifics.is_active());
1612   data.starter_pack_id = specifics.starter_pack_id();
1613
1614   std::unique_ptr<TemplateURL> turl(new TemplateURL(data));
1615   // If this TemplateURL matches a built-in prepopulated template URL, it's
1616   // possible that sync is trying to modify fields that should not be touched.
1617   // Revert these fields to the built-in values.
1618   UpdateTemplateURLIfPrepopulated(turl.get(), prefs);
1619
1620   DCHECK_EQ(TemplateURL::NORMAL, turl->type());
1621   if (reset_keyword || deduped) {
1622     if (reset_keyword)
1623       turl->ResetKeywordIfNecessary(search_terms_data, true);
1624     syncer::SyncData updated_sync_data = CreateSyncDataFromTemplateURL(*turl);
1625     change_list->push_back(syncer::SyncChange(
1626         FROM_HERE, syncer::SyncChange::ACTION_UPDATE, updated_sync_data));
1627   } else if (turl->IsGoogleSearchURLWithReplaceableKeyword(search_terms_data)) {
1628     if (!existing_turl) {
1629       // We're adding a new TemplateURL that uses the Google base URL, so set
1630       // its keyword appropriately for the local environment.
1631       turl->ResetKeywordIfNecessary(search_terms_data, false);
1632     } else if (existing_turl->IsGoogleSearchURLWithReplaceableKeyword(
1633         search_terms_data)) {
1634       // Ignore keyword changes triggered by the Google base URL changing on
1635       // another client.  If the base URL changes in this client as well, we'll
1636       // pick that up separately at the appropriate time.  Otherwise, changing
1637       // the keyword here could result in having the wrong keyword for the local
1638       // environment.
1639       turl->data_.SetKeyword(existing_turl->keyword());
1640     }
1641   }
1642
1643   return turl;
1644 }
1645
1646 // static
1647 SyncDataMap TemplateURLService::CreateGUIDToSyncDataMap(
1648     const syncer::SyncDataList& sync_data) {
1649   SyncDataMap data_map;
1650   for (auto i(sync_data.begin()); i != sync_data.end(); ++i)
1651     data_map[i->GetSpecifics().search_engine().sync_guid()] = *i;
1652   return data_map;
1653 }
1654
1655 void TemplateURLService::Init(const Initializer* initializers,
1656                               int num_initializers) {
1657   if (client_)
1658     client_->SetOwner(this);
1659
1660   if (prefs_) {
1661     pref_change_registrar_.Init(prefs_);
1662     pref_change_registrar_.Add(
1663         prefs::kSyncedDefaultSearchProviderGUID,
1664         base::BindRepeating(
1665             &TemplateURLService::OnSyncedDefaultSearchProviderGUIDChanged,
1666             base::Unretained(this)));
1667   }
1668
1669   DefaultSearchManager::Source source = DefaultSearchManager::FROM_USER;
1670   const TemplateURLData* dse =
1671       default_search_manager_.GetDefaultSearchEngine(&source);
1672
1673   Scoper scoper(this);
1674
1675   ApplyDefaultSearchChange(dse, source);
1676
1677   if (num_initializers > 0) {
1678     // This path is only hit by test code and is used to simulate a loaded
1679     // TemplateURLService.
1680     ChangeToLoadedState();
1681
1682     // Add specific initializers, if any.
1683     for (int i(0); i < num_initializers; ++i) {
1684       DCHECK(initializers[i].keyword);
1685       DCHECK(initializers[i].url);
1686       DCHECK(initializers[i].content);
1687
1688       // TemplateURLService ends up owning the TemplateURL, don't try and free
1689       // it.
1690       TemplateURLData data;
1691       data.SetShortName(base::UTF8ToUTF16(initializers[i].content));
1692       data.SetKeyword(base::UTF8ToUTF16(initializers[i].keyword));
1693       data.SetURL(initializers[i].url);
1694       // Set all to active by default for testing purposes.
1695       data.is_active = TemplateURLData::ActiveStatus::kTrue;
1696       Add(std::make_unique<TemplateURL>(data));
1697
1698       // Set the first provided identifier to be the default.
1699       if (i == 0)
1700         default_search_manager_.SetUserSelectedDefaultSearchEngine(data);
1701     }
1702   }
1703 }
1704
1705 void TemplateURLService::RemoveFromMaps(const TemplateURL* template_url) {
1706   const std::u16string& keyword = template_url->keyword();
1707
1708   // Remove from |keyword_to_turl_and_length_|. No need to find the best
1709   // fallback. We choose the best one as-needed from the multimap.
1710   const auto match_range = keyword_to_turl_and_length_.equal_range(keyword);
1711   for (auto it = match_range.first; it != match_range.second;) {
1712     if (it->second.first == template_url) {
1713       it = keyword_to_turl_and_length_.erase(it);
1714     } else {
1715       ++it;
1716     }
1717   }
1718
1719   if (template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)
1720     return;
1721
1722   if (!template_url->sync_guid().empty())
1723     guid_to_turl_.erase(template_url->sync_guid());
1724   // |provider_map_| is only initialized after loading has completed.
1725   if (loaded_) {
1726     provider_map_->Remove(template_url);
1727   }
1728 }
1729
1730 void TemplateURLService::AddToMaps(TemplateURL* template_url) {
1731   const std::u16string& keyword = template_url->keyword();
1732   keyword_to_turl_and_length_.insert(std::make_pair(
1733       keyword,
1734       TURLAndMeaningfulLength(
1735           template_url, GetMeaningfulKeywordLength(keyword, template_url))));
1736
1737   if (template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)
1738     return;
1739
1740   if (!template_url->sync_guid().empty())
1741     guid_to_turl_[template_url->sync_guid()] = template_url;
1742   // |provider_map_| is only initialized after loading has completed.
1743   if (loaded_)
1744     provider_map_->Add(template_url, search_terms_data());
1745 }
1746
1747 void TemplateURLService::SetTemplateURLs(
1748     std::unique_ptr<OwnedTemplateURLVector> urls) {
1749   Scoper scoper(this);
1750
1751   // Partition the URLs first, instead of implementing the loops below by simply
1752   // scanning the input twice.  While it's not supposed to happen normally, it's
1753   // possible for corrupt databases to return multiple entries with the same
1754   // keyword.  In this case, the first loop may delete the first entry when
1755   // adding the second.  If this happens, the second loop must not attempt to
1756   // access the deleted entry.  Partitioning ensures this constraint.
1757   auto first_invalid = std::partition(
1758       urls->begin(), urls->end(), [](const std::unique_ptr<TemplateURL>& turl) {
1759         return turl->id() != kInvalidTemplateURLID;
1760       });
1761
1762   // First, add the items that already have id's, so that the next_id_ gets
1763   // properly set.
1764   for (auto i = urls->begin(); i != first_invalid; ++i) {
1765     next_id_ = std::max(next_id_, (*i)->id());
1766     Add(std::move(*i), false);
1767   }
1768
1769   // Next add the new items that don't have id's.
1770   for (auto i = first_invalid; i != urls->end(); ++i)
1771     Add(std::move(*i));
1772 }
1773
1774 void TemplateURLService::ChangeToLoadedState() {
1775   DCHECK(!loaded_);
1776
1777   provider_map_->Init(template_urls_, search_terms_data());
1778   loaded_ = true;
1779
1780   ApplyDefaultSearchChangeNoMetrics(
1781       initial_default_search_provider_
1782           ? &initial_default_search_provider_->data()
1783           : nullptr,
1784       default_search_provider_source_);
1785   initial_default_search_provider_.reset();
1786
1787   if (on_loaded_callback_for_sync_)
1788     std::move(on_loaded_callback_for_sync_).Run();
1789
1790   on_loaded_callbacks_.Notify();
1791 }
1792
1793 bool TemplateURLService::CanAddAutogeneratedKeywordForHost(
1794     const std::string& host) const {
1795   const TemplateURLSet* urls = provider_map_->GetURLsForHost(host);
1796   if (!urls)
1797     return true;
1798
1799   return base::ranges::all_of(*urls, [](const TemplateURL* turl) {
1800     return turl->safe_for_autoreplace();
1801   });
1802 }
1803
1804 bool TemplateURLService::Update(TemplateURL* existing_turl,
1805                                 const TemplateURL& new_values) {
1806   DCHECK(existing_turl);
1807   DCHECK(!IsCreatedByExtension(existing_turl));
1808   if (!Contains(&template_urls_, existing_turl))
1809     return false;
1810
1811   Scoper scoper(this);
1812   model_mutated_notification_pending_ = true;
1813
1814   TemplateURLID previous_id = existing_turl->id();
1815   RemoveFromMaps(existing_turl);
1816
1817   // Update existing turl with new values and add back to the map.
1818   // We don't do any keyword conflict handling here, as TemplateURLService
1819   // already can pick the best engine out of duplicates. Replaceable duplicates
1820   // will be culled during next startup's Add() loop. We did this to keep
1821   // Update() simple: it never fails, and never deletes |existing_engine|.
1822   existing_turl->CopyFrom(new_values);
1823   existing_turl->data_.id = previous_id;
1824
1825   AddToMaps(existing_turl);
1826
1827   if (existing_turl->type() == TemplateURL::NORMAL) {
1828     if (web_data_service_)
1829       web_data_service_->UpdateKeyword(existing_turl->data());
1830
1831     // Inform sync of the update.
1832     ProcessTemplateURLChange(FROM_HERE, existing_turl,
1833                              syncer::SyncChange::ACTION_UPDATE);
1834   }
1835
1836   // Even if the DSE is controlled by an extension or policy, update the user
1837   // preferences as they may take over later.
1838   if (default_search_provider_source_ != DefaultSearchManager::FROM_FALLBACK)
1839     MaybeUpdateDSEViaPrefs(existing_turl);
1840
1841   return true;
1842 }
1843
1844 // static
1845 void TemplateURLService::UpdateTemplateURLIfPrepopulated(
1846     TemplateURL* template_url,
1847     PrefService* prefs) {
1848   int prepopulate_id = template_url->prepopulate_id();
1849   if (template_url->prepopulate_id() == 0)
1850     return;
1851
1852   std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
1853       TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs, nullptr);
1854
1855   for (const auto& url : prepopulated_urls) {
1856     if (url->prepopulate_id == prepopulate_id) {
1857       MergeIntoEngineData(template_url, url.get());
1858       template_url->CopyFrom(TemplateURL(*url));
1859     }
1860   }
1861 }
1862
1863 void TemplateURLService::MaybeUpdateDSEViaPrefs(TemplateURL* synced_turl) {
1864   if (prefs_ &&
1865       (synced_turl->sync_guid() ==
1866           prefs_->GetString(prefs::kSyncedDefaultSearchProviderGUID))) {
1867     default_search_manager_.SetUserSelectedDefaultSearchEngine(
1868         synced_turl->data());
1869   }
1870 }
1871
1872 void TemplateURLService::UpdateKeywordSearchTermsForURL(
1873     const URLVisitedDetails& details) {
1874   if (!details.url.is_valid())
1875     return;
1876
1877   const TemplateURLSet* urls_for_host =
1878       provider_map_->GetURLsForHost(details.url.host());
1879   if (!urls_for_host)
1880     return;
1881
1882   TemplateURL* visited_url = nullptr;
1883   for (auto i = urls_for_host->begin(); i != urls_for_host->end(); ++i) {
1884     std::u16string search_terms;
1885     if ((*i)->ExtractSearchTermsFromURL(details.url, search_terms_data(),
1886                                         &search_terms) &&
1887         !search_terms.empty()) {
1888       if (details.is_keyword_transition) {
1889         // The visit is the result of the user entering a keyword, generate a
1890         // KEYWORD_GENERATED visit for the KEYWORD so that the keyword typed
1891         // count is boosted.
1892         AddTabToSearchVisit(**i);
1893       }
1894       if (client_) {
1895         client_->SetKeywordSearchTermsForURL(
1896             details.url, (*i)->id(), search_terms);
1897       }
1898       // Caches the matched TemplateURL so its last_visited could be updated
1899       // later after iteration.
1900       // Note: Update() will replace the entry from the container of this
1901       // iterator, so update here directly will cause an error about it.
1902       if (!IsCreatedByExtension(*i))
1903         visited_url = *i;
1904     }
1905   }
1906   if (visited_url)
1907     UpdateTemplateURLVisitTime(visited_url);
1908 }
1909
1910 void TemplateURLService::UpdateTemplateURLVisitTime(TemplateURL* url) {
1911   TemplateURLData data(url->data());
1912   data.last_visited = clock_->Now();
1913   Update(url, TemplateURL(data));
1914 }
1915
1916 void TemplateURLService::AddTabToSearchVisit(const TemplateURL& t_url) {
1917   // Only add visits for entries the user hasn't modified. If the user modified
1918   // the entry the keyword may no longer correspond to the host name. It may be
1919   // possible to do something more sophisticated here, but it's so rare as to
1920   // not be worth it.
1921   if (!t_url.safe_for_autoreplace())
1922     return;
1923
1924   if (!client_)
1925     return;
1926
1927   GURL url(url_formatter::FixupURL(base::UTF16ToUTF8(t_url.keyword()),
1928                                    std::string()));
1929   if (!url.is_valid())
1930     return;
1931
1932   // Synthesize a visit for the keyword. This ensures the url for the keyword is
1933   // autocompleted even if the user doesn't type the url in directly.
1934   client_->AddKeywordGeneratedVisit(url);
1935 }
1936
1937 void TemplateURLService::ApplyDefaultSearchChange(
1938     const TemplateURLData* data,
1939     DefaultSearchManager::Source source) {
1940   if (!ApplyDefaultSearchChangeNoMetrics(data, source))
1941     return;
1942
1943   if (GetDefaultSearchProvider() &&
1944       GetDefaultSearchProvider()->HasGoogleBaseURLs(search_terms_data()) &&
1945       !dsp_change_callback_.is_null())
1946     dsp_change_callback_.Run();
1947 }
1948
1949 bool TemplateURLService::ApplyDefaultSearchChangeNoMetrics(
1950     const TemplateURLData* data,
1951     DefaultSearchManager::Source source) {
1952   // We do not want any sort of reentrancy while changing the default search
1953   // engine. This can occur when resolving conflicting entries. In those cases,
1954   // it's best to early exit and let the original process finish.
1955   if (applying_default_search_engine_change_)
1956     return false;
1957   base::AutoReset<bool> applying_change(&applying_default_search_engine_change_,
1958                                         true);
1959
1960   if (!loaded_) {
1961     // Set |initial_default_search_provider_| from the preferences. This is
1962     // mainly so we can hold ownership until we get to the point where the list
1963     // of keywords from Web Data is the owner of everything including the
1964     // default.
1965     bool changed = !TemplateURL::MatchesData(
1966         initial_default_search_provider_.get(), data, search_terms_data());
1967     TemplateURL::Type initial_engine_type =
1968         (source == DefaultSearchManager::FROM_EXTENSION)
1969             ? TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION
1970             : TemplateURL::NORMAL;
1971     initial_default_search_provider_ =
1972         data ? std::make_unique<TemplateURL>(*data, initial_engine_type)
1973              : nullptr;
1974     default_search_provider_source_ = source;
1975     return changed;
1976   }
1977
1978   // This may be deleted later. Use exclusively for pointer comparison to detect
1979   // a change.
1980   TemplateURL* previous_default_search_engine = default_search_provider_;
1981
1982   Scoper scoper(this);
1983
1984   if (default_search_provider_source_ == DefaultSearchManager::FROM_POLICY ||
1985       default_search_provider_source_ ==
1986           DefaultSearchManager::FROM_POLICY_RECOMMENDED ||
1987       source == DefaultSearchManager::FROM_POLICY ||
1988       source == DefaultSearchManager::FROM_POLICY_RECOMMENDED) {
1989     // We do this both to remove any no-longer-applicable policy-defined DSE as
1990     // well as to add the new one, if appropriate.
1991     UpdateProvidersCreatedByPolicy(
1992         &template_urls_,
1993         source == DefaultSearchManager::FROM_POLICY ||
1994                 source == DefaultSearchManager::FROM_POLICY_RECOMMENDED
1995             ? data
1996             : nullptr,
1997         /*is_mandatory=*/source == DefaultSearchManager::FROM_POLICY);
1998   }
1999
2000   // |default_search_provider_source_| must be set before calling Update(),
2001   // since that function needs to know the source of the update in question.
2002   default_search_provider_source_ = source;
2003
2004   if (!data) {
2005     default_search_provider_ = nullptr;
2006   } else if (source == DefaultSearchManager::FROM_EXTENSION) {
2007     default_search_provider_ = FindMatchingDefaultExtensionTemplateURL(*data);
2008     DCHECK(default_search_provider_);
2009   } else if (source == DefaultSearchManager::FROM_FALLBACK) {
2010     default_search_provider_ =
2011         FindPrepopulatedTemplateURL(data->prepopulate_id);
2012     if (default_search_provider_) {
2013       TemplateURLData update_data(*data);
2014       update_data.sync_guid = default_search_provider_->sync_guid();
2015
2016       // Now that we are auto-updating the favicon_url as the user browses,
2017       // respect the favicon_url entry in the database, instead of falling back
2018       // to the one in the prepopulated list.
2019       update_data.favicon_url = default_search_provider_->favicon_url();
2020
2021       if (!default_search_provider_->safe_for_autoreplace()) {
2022         update_data.safe_for_autoreplace = false;
2023         update_data.SetKeyword(default_search_provider_->keyword());
2024         update_data.SetShortName(default_search_provider_->short_name());
2025       }
2026       Update(default_search_provider_, TemplateURL(update_data));
2027     } else {
2028       // Normally the prepopulated fallback should be present in
2029       // |template_urls_|, but in a few cases it might not be:
2030       // (1) Tests that initialize the TemplateURLService in peculiar ways.
2031       // (2) If the user deleted the pre-populated default and we subsequently
2032       // lost their user-selected value.
2033       default_search_provider_ = Add(std::make_unique<TemplateURL>(*data));
2034       DCHECK(default_search_provider_)
2035           << "Add() to repair the DSE must never fail.";
2036     }
2037   } else if (source == DefaultSearchManager::FROM_USER) {
2038     default_search_provider_ = GetTemplateURLForGUID(data->sync_guid);
2039     if (!default_search_provider_ && data->prepopulate_id) {
2040       default_search_provider_ =
2041           FindPrepopulatedTemplateURL(data->prepopulate_id);
2042     }
2043     TemplateURLData new_data(*data);
2044     if (default_search_provider_) {
2045       Update(default_search_provider_, TemplateURL(new_data));
2046     } else {
2047       new_data.id = kInvalidTemplateURLID;
2048       default_search_provider_ = Add(std::make_unique<TemplateURL>(new_data));
2049       DCHECK(default_search_provider_)
2050           << "Add() to repair the DSE must never fail.";
2051     }
2052     if (default_search_provider_ && prefs_) {
2053       prefs_->SetString(prefs::kSyncedDefaultSearchProviderGUID,
2054                         default_search_provider_->sync_guid());
2055     }
2056   }
2057
2058   bool changed = default_search_provider_ != previous_default_search_engine;
2059   if (changed) {
2060     model_mutated_notification_pending_ = true;
2061   }
2062
2063   return changed;
2064 }
2065
2066 TemplateURL* TemplateURLService::Add(std::unique_ptr<TemplateURL> template_url,
2067                                      bool newly_adding) {
2068   DCHECK(template_url);
2069
2070   Scoper scoper(this);
2071
2072   if (newly_adding) {
2073     DCHECK_EQ(kInvalidTemplateURLID, template_url->id());
2074     DCHECK(!Contains(&template_urls_, template_url.get()));
2075     template_url->data_.id = ++next_id_;
2076   }
2077
2078   template_url->ResetKeywordIfNecessary(search_terms_data(), false);
2079
2080   // Early exit if the newly added TemplateURL was a replaceable duplicate.
2081   // No need to inform either Sync or flag on the model-mutated in that case.
2082   if (RemoveDuplicateReplaceableEnginesOf(template_url.get())) {
2083     return nullptr;
2084   }
2085
2086   TemplateURL* template_url_ptr = template_url.get();
2087   template_urls_.push_back(std::move(template_url));
2088   AddToMaps(template_url_ptr);
2089
2090   if (newly_adding && (template_url_ptr->type() == TemplateURL::NORMAL)) {
2091     if (web_data_service_)
2092       web_data_service_->AddKeyword(template_url_ptr->data());
2093
2094     // Inform sync of the addition. Note that this will assign a GUID to
2095     // template_url and add it to the guid_to_turl_.
2096     ProcessTemplateURLChange(FROM_HERE, template_url_ptr,
2097                              syncer::SyncChange::ACTION_ADD);
2098   }
2099
2100   if (template_url_ptr)
2101     model_mutated_notification_pending_ = true;
2102
2103   return template_url_ptr;
2104 }
2105
2106 // |template_urls| are the TemplateURLs loaded from the database.
2107 // |default_from_prefs| is the default search provider from the preferences, or
2108 // NULL if the DSE is not policy-defined.
2109 //
2110 // This function removes from the vector and the database all the TemplateURLs
2111 // that were set by policy, unless it is the current default search provider, in
2112 // which case it is updated with the data from prefs.
2113 void TemplateURLService::UpdateProvidersCreatedByPolicy(
2114     OwnedTemplateURLVector* template_urls,
2115     const TemplateURLData* default_from_prefs,
2116     bool is_mandatory) {
2117   DCHECK(template_urls);
2118
2119   Scoper scoper(this);
2120
2121   for (auto i = template_urls->begin(); i != template_urls->end();) {
2122     TemplateURL* template_url = i->get();
2123     if (template_url->created_by_policy()) {
2124       if (default_from_prefs &&
2125           TemplateURL::MatchesData(template_url, default_from_prefs,
2126                                    search_terms_data())) {
2127         // If the database specified a default search provider that was set
2128         // by policy, and the default search provider from the preferences
2129         // is also set by policy and they are the same, keep the entry in the
2130         // database and the |default_search_provider|.
2131         default_search_provider_ = template_url;
2132         // Prevent us from saving any other entries, or creating a new one.
2133         default_from_prefs = nullptr;
2134         ++i;
2135         continue;
2136       }
2137
2138       // If the previous default search provider was set as a recommended policy
2139       // and the new provider is not set by policy, keep the previous provider
2140       // in the database. This allows the recommended provider to remain in the
2141       // list if the user switches to a different provider.
2142       if (template_url->enforced_by_policy() || default_from_prefs) {
2143         TemplateURLID id = template_url->id();
2144         RemoveFromMaps(template_url);
2145         i = template_urls->erase(i);
2146         if (web_data_service_) {
2147           web_data_service_->RemoveKeyword(id);
2148         }
2149       } else {
2150         ++i;
2151       }
2152     } else {
2153       ++i;
2154     }
2155   }
2156
2157   if (default_from_prefs) {
2158     default_search_provider_ = nullptr;
2159     default_search_provider_source_ =
2160         is_mandatory ? DefaultSearchManager::FROM_POLICY
2161                      : DefaultSearchManager::FROM_POLICY_RECOMMENDED;
2162     TemplateURLData new_data(*default_from_prefs);
2163     if (new_data.sync_guid.empty())
2164       new_data.GenerateSyncGUID();
2165     new_data.created_by_policy = true;
2166     new_data.enforced_by_policy = is_mandatory;
2167     new_data.safe_for_autoreplace = false;
2168     new_data.is_active = TemplateURLData::ActiveStatus::kTrue;
2169     std::unique_ptr<TemplateURL> new_dse_ptr =
2170         std::make_unique<TemplateURL>(new_data);
2171     TemplateURL* new_dse = new_dse_ptr.get();
2172     if (Add(std::move(new_dse_ptr)))
2173       default_search_provider_ = new_dse;
2174   }
2175 }
2176
2177 void TemplateURLService::ResetTemplateURLGUID(TemplateURL* url,
2178                                               const std::string& guid) {
2179   DCHECK(loaded_);
2180   DCHECK(!guid.empty());
2181
2182   TemplateURLData data(url->data());
2183   data.sync_guid = guid;
2184   Update(url, TemplateURL(data));
2185 }
2186
2187 void TemplateURLService::MergeInSyncTemplateURL(
2188     TemplateURL* sync_turl,
2189     const SyncDataMap& sync_data,
2190     syncer::SyncChangeList* change_list,
2191     SyncDataMap* local_data) {
2192   DCHECK(sync_turl);
2193   DCHECK(!GetTemplateURLForGUID(sync_turl->sync_guid()));
2194   DCHECK(IsFromSync(sync_turl, sync_data));
2195
2196   bool should_add_sync_turl = true;
2197
2198   Scoper scoper(this);
2199
2200   // First resolve conflicts with local duplicate keyword NORMAL TemplateURLs,
2201   // working from best to worst.
2202   DCHECK(sync_turl->type() == TemplateURL::NORMAL);
2203   std::vector<TemplateURL*> local_duplicates;
2204   const auto match_range =
2205       keyword_to_turl_and_length_.equal_range(sync_turl->keyword());
2206   for (auto it = match_range.first; it != match_range.second; ++it) {
2207     TemplateURL* local_turl = it->second.first;
2208     // The conflict resolution code below sometimes resets the TemplateURL's
2209     // GUID, which can trigger deleting any Policy-created engines. Avoid this
2210     // use-after-free bug by excluding any Policy-created engines. Also exclude
2211     // Play API created engines, as those also seem local-only and should not
2212     // be merged into Synced engines. crbug.com/1414224.
2213     if (local_turl->type() == TemplateURL::NORMAL &&
2214         !local_turl->created_by_policy() &&
2215         !local_turl->created_from_play_api()) {
2216       local_duplicates.push_back(local_turl);
2217     }
2218   }
2219   base::ranges::sort(local_duplicates, [&](const auto& a, const auto& b) {
2220     return a->IsBetterThanEngineWithConflictingKeyword(b);
2221   });
2222   for (TemplateURL* conflicting_turl : local_duplicates) {
2223     if (IsFromSync(conflicting_turl, sync_data)) {
2224       // |conflicting_turl| is already known to Sync, so we're not allowed to
2225       // remove it. Just leave it. TemplateURLService can tolerate duplicates.
2226       // TODO(tommycli): Eventually we should figure out a way to merge
2227       // substantively identical ones or somehow otherwise cull the herd.
2228       continue;
2229     }
2230
2231     // |conflicting_turl| is not yet known to Sync. If it is better, then we
2232     // want to transfer its values up to sync. Otherwise, we remove it and
2233     // allow the entry from Sync to overtake it in the model.
2234     const std::string guid = conflicting_turl->sync_guid();
2235     if (conflicting_turl == GetDefaultSearchProvider() ||
2236         conflicting_turl->IsBetterThanEngineWithConflictingKeyword(sync_turl)) {
2237       ResetTemplateURLGUID(conflicting_turl, sync_turl->sync_guid());
2238       syncer::SyncData updated_sync_data =
2239           CreateSyncDataFromTemplateURL(*conflicting_turl);
2240       change_list->push_back(syncer::SyncChange(
2241           FROM_HERE, syncer::SyncChange::ACTION_UPDATE, updated_sync_data));
2242       // Note that in this case we do not add the Sync TemplateURL to the
2243       // local model, since we've effectively "merged" it in by updating the
2244       // local conflicting entry with its sync_guid.
2245       should_add_sync_turl = false;
2246     } else {
2247       // We guarantee that this isn't the local search provider. Otherwise,
2248       // local would have won.
2249       DCHECK(conflicting_turl != GetDefaultSearchProvider());
2250       Remove(conflicting_turl);
2251     }
2252     // This TemplateURL was either removed or overwritten in the local model.
2253     // Remove the entry from the local data so it isn't pushed up to Sync.
2254     local_data->erase(guid);
2255   }
2256
2257   // Try to take over a local built-in (prepopulated or starter pack) entry,
2258   // assuming we haven't already run into a keyword conflict.
2259   if (local_duplicates.empty() &&
2260       (sync_turl->prepopulate_id() != 0 || sync_turl->starter_pack_id() != 0)) {
2261     // Check for a turl with a conflicting prepopulate_id. This detects the case
2262     // where the user changes a prepopulated engine's keyword on one client,
2263     // then begins syncing on another client.  We want to reflect this keyword
2264     // change to that prepopulated URL on other clients instead of assuming that
2265     // the modified TemplateURL is a new entity.
2266     TemplateURL* conflicting_built_in_turl =
2267         (sync_turl->prepopulate_id() != 0)
2268             ? FindPrepopulatedTemplateURL(sync_turl->prepopulate_id())
2269             : FindStarterPackTemplateURL(sync_turl->starter_pack_id());
2270
2271     // If we found a conflict, and the sync entity is better, apply the remote
2272     // changes locally. We consider |sync_turl| better if it's been modified
2273     // more recently and the local TemplateURL isn't yet known to sync. We will
2274     // consider the sync entity better even if the local TemplateURL is the
2275     // current default, since in this case being default does not necessarily
2276     // mean the user explicitly set this TemplateURL as default. If we didn't do
2277     // this, changes to the keywords of prepopulated default engines would never
2278     // be applied to other clients.
2279     // If we can't safely replace the local entry with the synced one, or merge
2280     // the relevant changes in, we give up and leave both intact.
2281     if (conflicting_built_in_turl &&
2282         !IsFromSync(conflicting_built_in_turl, sync_data) &&
2283         sync_turl->IsBetterThanEngineWithConflictingKeyword(
2284             conflicting_built_in_turl)) {
2285       std::string guid = conflicting_built_in_turl->sync_guid();
2286       if (conflicting_built_in_turl == default_search_provider_) {
2287         bool pref_matched =
2288             prefs_->GetString(prefs::kSyncedDefaultSearchProviderGUID) ==
2289             default_search_provider_->sync_guid();
2290         // Update the existing engine in-place.
2291         Update(default_search_provider_, TemplateURL(sync_turl->data()));
2292         // If prefs::kSyncedDefaultSearchProviderGUID matched
2293         // |default_search_provider_|'s GUID before, then update it to match its
2294         // new GUID. If the pref didn't match before, then it probably refers to
2295         // a new search engine from Sync which just hasn't been added locally
2296         // yet, so leave it alone in that case.
2297         if (pref_matched) {
2298           prefs_->SetString(prefs::kSyncedDefaultSearchProviderGUID,
2299                             default_search_provider_->sync_guid());
2300         }
2301
2302         should_add_sync_turl = false;
2303       } else {
2304         Remove(conflicting_built_in_turl);
2305       }
2306       // Remove the local data so it isn't written to sync.
2307       local_data->erase(guid);
2308     }
2309   }
2310
2311   if (should_add_sync_turl) {
2312     // Force the local ID to kInvalidTemplateURLID so we can add it.
2313     TemplateURLData data(sync_turl->data());
2314     data.id = kInvalidTemplateURLID;
2315     std::unique_ptr<TemplateURL> added_ptr =
2316         std::make_unique<TemplateURL>(data);
2317     TemplateURL* added = added_ptr.get();
2318     base::AutoReset<DefaultSearchChangeOrigin> change_origin(
2319         &dsp_change_origin_, DSP_CHANGE_SYNC_ADD);
2320     if (Add(std::move(added_ptr)))
2321       MaybeUpdateDSEViaPrefs(added);
2322   }
2323 }
2324
2325 void TemplateURLService::PatchMissingSyncGUIDs(
2326     OwnedTemplateURLVector* template_urls) {
2327   DCHECK(template_urls);
2328   for (auto& template_url : *template_urls) {
2329     DCHECK(template_url);
2330     if (template_url->sync_guid().empty() &&
2331         (template_url->type() == TemplateURL::NORMAL)) {
2332       template_url->data_.GenerateSyncGUID();
2333       if (web_data_service_)
2334         web_data_service_->UpdateKeyword(template_url->data());
2335     }
2336   }
2337 }
2338
2339 void TemplateURLService::OnSyncedDefaultSearchProviderGUIDChanged() {
2340   base::AutoReset<DefaultSearchChangeOrigin> change_origin(
2341       &dsp_change_origin_, DSP_CHANGE_SYNC_PREF);
2342
2343   std::string new_guid =
2344       prefs_->GetString(prefs::kSyncedDefaultSearchProviderGUID);
2345   if (new_guid.empty()) {
2346     default_search_manager_.ClearUserSelectedDefaultSearchEngine();
2347     return;
2348   }
2349
2350   const TemplateURL* turl = GetTemplateURLForGUID(new_guid);
2351   if (turl)
2352     default_search_manager_.SetUserSelectedDefaultSearchEngine(turl->data());
2353 }
2354
2355 void TemplateURLService::MaybeSetIsActiveSearchEngines(
2356     OwnedTemplateURLVector* template_urls) {
2357   DCHECK(template_urls);
2358   for (auto& turl : *template_urls) {
2359     DCHECK(turl);
2360     // An turl is "active" if it has ever been used or manually added/modified.
2361     // |safe_for_autoreplace| is false if the entry has been modified.
2362     if (turl->is_active() == TemplateURLData::ActiveStatus::kUnspecified &&
2363         (!turl->safe_for_autoreplace() || turl->usage_count() > 0)) {
2364       turl->data_.is_active = TemplateURLData::ActiveStatus::kTrue;
2365       turl->data_.safe_for_autoreplace = false;
2366       if (web_data_service_)
2367         web_data_service_->UpdateKeyword(turl->data());
2368     }
2369   }
2370 }
2371
2372 template <typename Container>
2373 void TemplateURLService::AddMatchingKeywordsHelper(
2374     const Container& keyword_to_turl_and_length,
2375     const std::u16string& prefix,
2376     bool supports_replacement_only,
2377     TURLsAndMeaningfulLengths* matches) {
2378   // Sanity check args.
2379   if (prefix.empty())
2380     return;
2381   DCHECK(matches);
2382
2383   // Find matching keyword range.  Searches the element map for keywords
2384   // beginning with |prefix| and stores the endpoints of the resulting set in
2385   // |match_range|.
2386   const auto match_range(std::equal_range(
2387       keyword_to_turl_and_length.begin(), keyword_to_turl_and_length.end(),
2388       typename Container::value_type(prefix,
2389                                      TURLAndMeaningfulLength(nullptr, 0)),
2390       LessWithPrefix()));
2391
2392   // Add to vector of matching keywords.
2393   for (typename Container::const_iterator i(match_range.first);
2394     i != match_range.second; ++i) {
2395     if (!supports_replacement_only ||
2396         i->second.first->url_ref().SupportsReplacement(search_terms_data()))
2397       matches->push_back(i->second);
2398   }
2399 }
2400
2401 TemplateURL* TemplateURLService::FindPrepopulatedTemplateURL(
2402     int prepopulated_id) {
2403   DCHECK(prepopulated_id);
2404   for (const auto& turl : template_urls_) {
2405     if (turl->prepopulate_id() == prepopulated_id)
2406       return turl.get();
2407   }
2408   return nullptr;
2409 }
2410
2411 TemplateURL* TemplateURLService::FindStarterPackTemplateURL(
2412     int starter_pack_id) {
2413   DCHECK(starter_pack_id);
2414   for (const auto& turl : template_urls_) {
2415     if (turl->starter_pack_id() == starter_pack_id)
2416       return turl.get();
2417   }
2418   return nullptr;
2419 }
2420
2421 TemplateURL* TemplateURLService::FindTemplateURLForExtension(
2422     const std::string& extension_id,
2423     TemplateURL::Type type) {
2424   DCHECK_NE(TemplateURL::NORMAL, type);
2425   for (const auto& turl : template_urls_) {
2426     if (turl->type() == type && turl->GetExtensionId() == extension_id)
2427       return turl.get();
2428   }
2429   return nullptr;
2430 }
2431
2432 TemplateURL* TemplateURLService::FindMatchingDefaultExtensionTemplateURL(
2433     const TemplateURLData& data) {
2434   for (const auto& turl : template_urls_) {
2435     if (turl->type() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION &&
2436         turl->extension_info_->wants_to_be_default_engine &&
2437         TemplateURL::MatchesData(turl.get(), &data, search_terms_data()))
2438       return turl.get();
2439   }
2440   return nullptr;
2441 }
2442
2443 bool TemplateURLService::RemoveDuplicateReplaceableEnginesOf(
2444     TemplateURL* candidate) {
2445   DCHECK(candidate);
2446   const std::u16string& keyword = candidate->keyword();
2447
2448   // If there's not at least one conflicting TemplateURL, there's nothing to do.
2449   const auto match_range = keyword_to_turl_and_length_.equal_range(keyword);
2450   if (match_range.first == match_range.second) {
2451     return false;
2452   }
2453
2454   // Gather the replaceable TemplateURLs to be removed. We don't do it in-place,
2455   // because Remove() invalidates iterators.
2456   std::vector<TemplateURL*> replaceable_turls;
2457   for (auto it = match_range.first; it != match_range.second; ++it) {
2458     TemplateURL* turl = it->second.first;
2459     DCHECK_NE(turl, candidate) << "This algorithm runs BEFORE |candidate| is "
2460                                   "added to the keyword map.";
2461
2462     // Built-in engines are marked as safe_for_autoreplace(). But because
2463     // they are shown in the Default Search Engines Settings UI, users would
2464     // find it confusing if they were ever automatically removed.
2465     // https://crbug.com/1164024
2466     if (turl->safe_for_autoreplace() && turl->prepopulate_id() == 0 &&
2467         turl->starter_pack_id() == 0) {
2468       replaceable_turls.push_back(turl);
2469     }
2470   }
2471
2472   // Find the BEST engine for |keyword| factoring in the new |candidate|.
2473   TemplateURL* best = GetTemplateURLForKeyword(keyword);
2474   if (!best || candidate->IsBetterThanEngineWithConflictingKeyword(best)) {
2475     best = candidate;
2476   }
2477
2478   // Remove all the replaceable TemplateURLs that are not the best.
2479   for (TemplateURL* turl : replaceable_turls) {
2480     DCHECK_NE(turl, candidate);
2481
2482     // Never actually remove the DSE during this phase. This handling defers
2483     // deleting the DSE until it's no longer set as the DSE, analagous to how
2484     // we handle ACTION_DELETE of the DSE in ProcessSyncChanges().
2485     if (turl != best && !MatchesDefaultSearchProvider(turl)) {
2486       Remove(turl);
2487     }
2488   }
2489
2490   // Caller needs to know if |candidate| would have been deleted.
2491   // Also always successfully add prepopulated engines, for two reasons:
2492   //  1. The DSE repair logic in ApplyDefaultSearchChangeNoMetrics() relies on
2493   //     Add()ing back the DSE always succeeding. https://crbug.com/1164024
2494   //  2. If we don't do this, we have a weird order-dependence on the
2495   //     replaceability of prepopulated engines, given that we refuse to add
2496   //     prepopulated engines to the |replaceable_engines| vector.
2497   //
2498   // Given the necessary special casing of prepopulated engines, we may consider
2499   // marking prepopulated engines as NOT safe_for_autoreplace(), but there's a
2500   // few obstacles to this:
2501   //  1. Prepopulated engines are not user-created, and therefore meet the
2502   //     definition of safe_for_autoreplace().
2503   //  2. If we mark them as NOT safe_for_autoreplace(), we can no longer
2504   //     distinguish between prepopulated engines that user has edited, vs. not
2505   //     edited.
2506   //
2507   // One more caveat: In 2019, we made prepopulated engines have a
2508   // deterministically generated Sync GUID in order to prevent duplicate
2509   // prepopulated engines when two clients start syncing at the same time.
2510   // When combined with the requirement that we can never fail to add a
2511   // prepopulated engine, this could leads to two engines having the same GUID.
2512   //
2513   // TODO(tommycli): After M89, we need to investigate solving the contradiction
2514   // above. Most probably: the solution is to stop Syncing prepopulated engines
2515   // and make the GUIDs actually globally unique again.
2516   return candidate != best && candidate->safe_for_autoreplace() &&
2517          candidate->prepopulate_id() == 0 && candidate->starter_pack_id() == 0;
2518 }
2519
2520 bool TemplateURLService::MatchesDefaultSearchProvider(TemplateURL* turl) const {
2521   DCHECK(turl);
2522   const TemplateURL* default_provider = GetDefaultSearchProvider();
2523   if (!default_provider)
2524     return false;
2525
2526   return turl->sync_guid() == default_provider->sync_guid();
2527 }