1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
6
7#include "base/guid.h"
8#include "base/location.h"
9#include "base/logging.h"
10#include "base/strings/utf_string_conversions.h"
11#include "components/autofill/core/browser/autofill_country.h"
12#include "components/autofill/core/browser/autofill_profile.h"
13#include "components/autofill/core/browser/form_group.h"
14#include "components/autofill/core/browser/webdata/autofill_table.h"
15#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
16#include "components/webdata/common/web_database.h"
17#include "sync/api/sync_error.h"
18#include "sync/api/sync_error_factory.h"
19#include "sync/protocol/sync.pb.h"
20
21using base::ASCIIToUTF16;
22using base::UTF8ToUTF16;
23using base::UTF16ToUTF8;
24
25namespace autofill {
26
27namespace {
28
29std::string LimitData(const std::string& data) {
30  std::string sanitized_value(data);
31  if (sanitized_value.length() > AutofillTable::kMaxDataLength)
32    sanitized_value.resize(AutofillTable::kMaxDataLength);
33  return sanitized_value;
34}
35
36void* UserDataKey() {
37  // Use the address of a static that COMDAT folding won't ever fold
38  // with something else.
39  static int user_data_key = 0;
40  return reinterpret_cast<void*>(&user_data_key);
41}
42
43}  // namespace
44
45const char kAutofillProfileTag[] = "google_chrome_autofill_profiles";
46
47AutofillProfileSyncableService::AutofillProfileSyncableService(
48    AutofillWebDataBackend* webdata_backend,
49    const std::string& app_locale)
50    : webdata_backend_(webdata_backend),
51      app_locale_(app_locale),
52      scoped_observer_(this) {
53  DCHECK(webdata_backend_);
54
55  scoped_observer_.Add(webdata_backend_);
56}
57
58AutofillProfileSyncableService::~AutofillProfileSyncableService() {
59  DCHECK(CalledOnValidThread());
60}
61
62// static
63void AutofillProfileSyncableService::CreateForWebDataServiceAndBackend(
64    AutofillWebDataService* web_data_service,
65    AutofillWebDataBackend* webdata_backend,
66    const std::string& app_locale) {
67  web_data_service->GetDBUserData()->SetUserData(
68      UserDataKey(),
69      new AutofillProfileSyncableService(webdata_backend, app_locale));
70}
71
72// static
73AutofillProfileSyncableService*
74AutofillProfileSyncableService::FromWebDataService(
75    AutofillWebDataService* web_data_service) {
76  return static_cast<AutofillProfileSyncableService*>(
77      web_data_service->GetDBUserData()->GetUserData(UserDataKey()));
78}
79
80AutofillProfileSyncableService::AutofillProfileSyncableService()
81    : webdata_backend_(NULL),
82      scoped_observer_(this) {
83}
84
85syncer::SyncMergeResult
86AutofillProfileSyncableService::MergeDataAndStartSyncing(
87    syncer::ModelType type,
88    const syncer::SyncDataList& initial_sync_data,
89    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
90    scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
91  DCHECK(CalledOnValidThread());
92  DCHECK(!sync_processor_.get());
93  DCHECK(sync_processor.get());
94  DCHECK(sync_error_factory.get());
95  DVLOG(1) << "Associating Autofill: MergeDataAndStartSyncing";
96
97  syncer::SyncMergeResult merge_result(type);
98  sync_error_factory_ = sync_error_factory.Pass();
99  if (!LoadAutofillData(&profiles_.get())) {
100    merge_result.set_error(sync_error_factory_->CreateAndUploadError(
101        FROM_HERE, "Could not get the autofill data from WebDatabase."));
102    return merge_result;
103  }
104
105  if (DLOG_IS_ON(INFO)) {
106    DVLOG(2) << "[AUTOFILL MIGRATION]"
107             << "Printing profiles from web db";
108
109    for (ScopedVector<AutofillProfile>::const_iterator ix =
110         profiles_.begin(); ix != profiles_.end(); ++ix) {
111      AutofillProfile* p = *ix;
112      DVLOG(2) << "[AUTOFILL MIGRATION]  "
113               << UTF16ToUTF8(p->GetRawInfo(NAME_FIRST))
114               << UTF16ToUTF8(p->GetRawInfo(NAME_LAST))
115               << p->guid();
116    }
117  }
118
119  sync_processor_ = sync_processor.Pass();
120
121  GUIDToProfileMap remaining_profiles;
122  CreateGUIDToProfileMap(profiles_.get(), &remaining_profiles);
123
124  DataBundle bundle;
125  // Go through and check for all the profiles that sync already knows about.
126  for (syncer::SyncDataList::const_iterator sync_iter =
127           initial_sync_data.begin();
128       sync_iter != initial_sync_data.end();
129       ++sync_iter) {
130    GUIDToProfileMap::iterator it =
131        CreateOrUpdateProfile(*sync_iter, &remaining_profiles, &bundle);
132    // |it| points to created/updated profile. Add it to the |profiles_map_| and
133    // then remove it from |remaining_profiles|. After this loop is completed
134    // |remaining_profiles| will have only those profiles that are not in the
135    // sync.
136    profiles_map_[it->first] = it->second;
137    remaining_profiles.erase(it);
138  }
139
140  // Check for similar unmatched profiles - they are created independently on
141  // two systems, so merge them.
142  for (GUIDToProfileMap::iterator it = bundle.candidates_to_merge.begin();
143       it != bundle.candidates_to_merge.end(); ++it) {
144    GUIDToProfileMap::iterator profile_to_merge =
145        remaining_profiles.find(it->first);
146    if (profile_to_merge != remaining_profiles.end()) {
147      bundle.profiles_to_delete.push_back(profile_to_merge->second->guid());
148      if (MergeProfile(*(profile_to_merge->second), it->second, app_locale_))
149        bundle.profiles_to_sync_back.push_back(it->second);
150      DVLOG(2) << "[AUTOFILL SYNC]"
151               << "Found similar profile in sync db but with a different guid: "
152               << UTF16ToUTF8(it->second->GetRawInfo(NAME_FIRST))
153               << UTF16ToUTF8(it->second->GetRawInfo(NAME_LAST))
154               << "New guid " << it->second->guid()
155               << ". Profile to be deleted "
156               << profile_to_merge->second->guid();
157      remaining_profiles.erase(profile_to_merge);
158    }
159  }
160
161  if (!SaveChangesToWebData(bundle)) {
162    merge_result.set_error(sync_error_factory_->CreateAndUploadError(
163        FROM_HERE,
164        "Failed to update webdata."));
165    return merge_result;
166  }
167
168  syncer::SyncChangeList new_changes;
169  for (GUIDToProfileMap::iterator i = remaining_profiles.begin();
170       i != remaining_profiles.end(); ++i) {
171    new_changes.push_back(
172        syncer::SyncChange(FROM_HERE,
173                           syncer::SyncChange::ACTION_ADD,
174                           CreateData(*(i->second))));
175    profiles_map_[i->first] = i->second;
176  }
177
178  for (size_t i = 0; i < bundle.profiles_to_sync_back.size(); ++i) {
179    new_changes.push_back(
180        syncer::SyncChange(FROM_HERE,
181                           syncer::SyncChange::ACTION_UPDATE,
182                           CreateData(*(bundle.profiles_to_sync_back[i]))));
183  }
184
185  if (!new_changes.empty()) {
186    merge_result.set_error(
187        sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes));
188  }
189
190  if (webdata_backend_)
191    webdata_backend_->NotifyOfMultipleAutofillChanges();
192
193  return merge_result;
194}
195
196void AutofillProfileSyncableService::StopSyncing(syncer::ModelType type) {
197  DCHECK(CalledOnValidThread());
198  DCHECK_EQ(type, syncer::AUTOFILL_PROFILE);
199
200  sync_processor_.reset();
201  sync_error_factory_.reset();
202  profiles_.clear();
203  profiles_map_.clear();
204}
205
206syncer::SyncDataList AutofillProfileSyncableService::GetAllSyncData(
207    syncer::ModelType type) const {
208  DCHECK(CalledOnValidThread());
209  DCHECK(sync_processor_.get());
210  DCHECK_EQ(type, syncer::AUTOFILL_PROFILE);
211
212  syncer::SyncDataList current_data;
213
214  for (GUIDToProfileMap::const_iterator i = profiles_map_.begin();
215       i != profiles_map_.end(); ++i) {
216    current_data.push_back(CreateData(*(i->second)));
217  }
218  return current_data;
219}
220
221syncer::SyncError AutofillProfileSyncableService::ProcessSyncChanges(
222    const tracked_objects::Location& from_here,
223    const syncer::SyncChangeList& change_list) {
224  DCHECK(CalledOnValidThread());
225  if (!sync_processor_.get()) {
226    syncer::SyncError error(FROM_HERE,
227                            syncer::SyncError::DATATYPE_ERROR,
228                            "Models not yet associated.",
229                            syncer::AUTOFILL_PROFILE);
230    return error;
231  }
232
233  DataBundle bundle;
234
235  for (syncer::SyncChangeList::const_iterator i = change_list.begin();
236       i != change_list.end(); ++i) {
237    DCHECK(i->IsValid());
238    switch (i->change_type()) {
239      case syncer::SyncChange::ACTION_ADD:
240      case syncer::SyncChange::ACTION_UPDATE:
241        CreateOrUpdateProfile(i->sync_data(), &profiles_map_, &bundle);
242        break;
243      case syncer::SyncChange::ACTION_DELETE: {
244        std::string guid = i->sync_data().GetSpecifics().
245             autofill_profile().guid();
246        bundle.profiles_to_delete.push_back(guid);
247        profiles_map_.erase(guid);
248      } break;
249      default:
250        NOTREACHED() << "Unexpected sync change state.";
251        return sync_error_factory_->CreateAndUploadError(
252              FROM_HERE,
253              "ProcessSyncChanges failed on ChangeType " +
254                  syncer::SyncChange::ChangeTypeToString(i->change_type()));
255    }
256  }
257
258  if (!SaveChangesToWebData(bundle)) {
259    return sync_error_factory_->CreateAndUploadError(
260        FROM_HERE,
261        "Failed to update webdata.");
262  }
263
264  if (webdata_backend_)
265    webdata_backend_->NotifyOfMultipleAutofillChanges();
266
267  return syncer::SyncError();
268}
269
270void AutofillProfileSyncableService::AutofillProfileChanged(
271    const AutofillProfileChange& change) {
272  // Check if sync is on. If we receive notification prior to the sync being set
273  // up we are going to process all when MergeData..() is called. If we receive
274  // notification after the sync exited, it will be sinced next time Chrome
275  // starts.
276  if (sync_processor_.get()) {
277    ActOnChange(change);
278  } else if (!flare_.is_null()) {
279    flare_.Run(syncer::AUTOFILL_PROFILE);
280    flare_.Reset();
281  }
282}
283
284bool AutofillProfileSyncableService::LoadAutofillData(
285    std::vector<AutofillProfile*>* profiles) {
286  return GetAutofillTable()->GetAutofillProfiles(profiles);
287}
288
289bool AutofillProfileSyncableService::SaveChangesToWebData(
290    const DataBundle& bundle) {
291  DCHECK(CalledOnValidThread());
292
293  AutofillTable* autofill_table = GetAutofillTable();
294
295  bool success = true;
296  for (size_t i = 0; i< bundle.profiles_to_delete.size(); ++i) {
297    if (!autofill_table->RemoveAutofillProfile(bundle.profiles_to_delete[i]))
298      success = false;
299  }
300
301  for (size_t i = 0; i < bundle.profiles_to_add.size(); i++) {
302    if (!autofill_table->AddAutofillProfile(*bundle.profiles_to_add[i]))
303      success = false;
304  }
305
306  for (size_t i = 0; i < bundle.profiles_to_update.size(); i++) {
307    if (!autofill_table->UpdateAutofillProfile(*bundle.profiles_to_update[i]))
308      success = false;
309  }
310  return success;
311}
312
313// static
314bool AutofillProfileSyncableService::OverwriteProfileWithServerData(
315    const sync_pb::AutofillProfileSpecifics& specifics,
316    AutofillProfile* profile,
317    const std::string& app_locale) {
318  bool diff = false;
319  if (specifics.has_origin() && profile->origin() != specifics.origin()) {
320    bool was_verified = profile->IsVerified();
321    profile->set_origin(specifics.origin());
322    diff = true;
323
324    // Verified profiles should never be overwritten by unverified ones.
325    DCHECK(!was_verified || profile->IsVerified());
326  }
327
328  // Update all multivalued fields: names, emails, and phones.
329  diff = UpdateMultivaluedField(NAME_FIRST,
330                                specifics.name_first(), profile) || diff;
331  diff = UpdateMultivaluedField(NAME_MIDDLE,
332                                specifics.name_middle(), profile) || diff;
333  diff = UpdateMultivaluedField(NAME_LAST,
334                                specifics.name_last(), profile) || diff;
335  // Older versions don't have a separate full name; don't overwrite full name
336  // in this case.
337  if (specifics.name_full().size() > 0) {
338    diff = UpdateMultivaluedField(NAME_FULL,
339                                  specifics.name_full(), profile) || diff;
340  }
341  diff = UpdateMultivaluedField(EMAIL_ADDRESS,
342                                specifics.email_address(), profile) || diff;
343  diff = UpdateMultivaluedField(PHONE_HOME_WHOLE_NUMBER,
344                                specifics.phone_home_whole_number(),
345                                profile) || diff;
346
347  // Update all simple single-valued address fields.
348  diff = UpdateField(COMPANY_NAME, specifics.company_name(), profile) || diff;
349  diff = UpdateField(ADDRESS_HOME_CITY,
350                     specifics.address_home_city(), profile) || diff;
351  diff = UpdateField(ADDRESS_HOME_STATE,
352                     specifics.address_home_state(), profile) || diff;
353  diff = UpdateField(ADDRESS_HOME_ZIP,
354                     specifics.address_home_zip(), profile) || diff;
355  diff = UpdateField(ADDRESS_HOME_SORTING_CODE,
356                     specifics.address_home_sorting_code(), profile) || diff;
357  diff = UpdateField(ADDRESS_HOME_DEPENDENT_LOCALITY,
358                     specifics.address_home_dependent_locality(),
359                     profile) || diff;
360
361  // Update the country field, which can contain either a country code (if set
362  // by a newer version of Chrome), or a country name (if set by an older
363  // version of Chrome).
364  base::string16 country_name_or_code =
365      ASCIIToUTF16(specifics.address_home_country());
366  std::string country_code =
367      AutofillCountry::GetCountryCode(country_name_or_code, app_locale);
368  diff = UpdateField(ADDRESS_HOME_COUNTRY, country_code, profile) || diff;
369
370  // Update the street address.  In newer versions of Chrome (M34+), this data
371  // is stored in the |address_home_street_address| field.  In older versions,
372  // this data is stored separated out by address line.
373  if (specifics.has_address_home_street_address()) {
374    diff = UpdateField(ADDRESS_HOME_STREET_ADDRESS,
375                       specifics.address_home_street_address(),
376                       profile) || diff;
377  } else {
378    diff = UpdateField(ADDRESS_HOME_LINE1,
379                       specifics.address_home_line1(), profile) || diff;
380    diff = UpdateField(ADDRESS_HOME_LINE2,
381                       specifics.address_home_line2(), profile) || diff;
382  }
383
384  // Update the BCP 47 language code that can be used to format the address for
385  // display.
386  if (specifics.has_address_home_language_code() &&
387      specifics.address_home_language_code() != profile->language_code()) {
388    profile->set_language_code(specifics.address_home_language_code());
389    diff = true;
390  }
391
392  return diff;
393}
394
395// static
396void AutofillProfileSyncableService::WriteAutofillProfile(
397    const AutofillProfile& profile,
398    sync_pb::EntitySpecifics* profile_specifics) {
399  sync_pb::AutofillProfileSpecifics* specifics =
400      profile_specifics->mutable_autofill_profile();
401
402  DCHECK(base::IsValidGUID(profile.guid()));
403
404  // Reset all multi-valued fields in the protobuf.
405  specifics->clear_name_first();
406  specifics->clear_name_middle();
407  specifics->clear_name_last();
408  specifics->clear_name_full();
409  specifics->clear_email_address();
410  specifics->clear_phone_home_whole_number();
411
412  specifics->set_guid(profile.guid());
413  specifics->set_origin(profile.origin());
414
415  std::vector<base::string16> values;
416  profile.GetRawMultiInfo(NAME_FIRST, &values);
417  for (size_t i = 0; i < values.size(); ++i) {
418    specifics->add_name_first(LimitData(UTF16ToUTF8(values[i])));
419  }
420
421  profile.GetRawMultiInfo(NAME_MIDDLE, &values);
422  for (size_t i = 0; i < values.size(); ++i) {
423    specifics->add_name_middle(LimitData(UTF16ToUTF8(values[i])));
424  }
425
426  profile.GetRawMultiInfo(NAME_LAST, &values);
427  for (size_t i = 0; i < values.size(); ++i) {
428    specifics->add_name_last(LimitData(UTF16ToUTF8(values[i])));
429  }
430
431  profile.GetRawMultiInfo(NAME_FULL, &values);
432  for (size_t i = 0; i < values.size(); ++i) {
433    specifics->add_name_full(LimitData(UTF16ToUTF8(values[i])));
434  }
435
436  specifics->set_address_home_line1(
437      LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))));
438  specifics->set_address_home_line2(
439      LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))));
440  specifics->set_address_home_city(
441      LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))));
442  specifics->set_address_home_state(
443      LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))));
444  specifics->set_address_home_zip(
445      LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))));
446  specifics->set_address_home_country(
447      LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))));
448  specifics->set_address_home_street_address(
449      LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS))));
450  specifics->set_address_home_sorting_code(
451      LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE))));
452  specifics->set_address_home_dependent_locality(
453      LimitData(
454          UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))));
455  specifics->set_address_home_language_code(LimitData(profile.language_code()));
456
457  profile.GetRawMultiInfo(EMAIL_ADDRESS, &values);
458  for (size_t i = 0; i < values.size(); ++i) {
459    specifics->add_email_address(LimitData(UTF16ToUTF8(values[i])));
460  }
461
462  specifics->set_company_name(
463      LimitData(UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))));
464
465  profile.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
466  for (size_t i = 0; i < values.size(); ++i) {
467    specifics->add_phone_home_whole_number(LimitData(UTF16ToUTF8(values[i])));
468  }
469}
470
471void AutofillProfileSyncableService::CreateGUIDToProfileMap(
472    const std::vector<AutofillProfile*>& profiles,
473    GUIDToProfileMap* profile_map) {
474  DCHECK(profile_map);
475  profile_map->clear();
476  for (size_t i = 0; i < profiles.size(); ++i)
477    (*profile_map)[profiles[i]->guid()] = profiles[i];
478}
479
480AutofillProfileSyncableService::GUIDToProfileMap::iterator
481AutofillProfileSyncableService::CreateOrUpdateProfile(
482    const syncer::SyncData& data,
483    GUIDToProfileMap* profile_map,
484    DataBundle* bundle) {
485  DCHECK(profile_map);
486  DCHECK(bundle);
487
488  DCHECK_EQ(syncer::AUTOFILL_PROFILE, data.GetDataType());
489
490  const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
491  const sync_pb::AutofillProfileSpecifics& autofill_specifics(
492      specifics.autofill_profile());
493
494  GUIDToProfileMap::iterator existing_profile = profile_map->find(
495        autofill_specifics.guid());
496  if (existing_profile != profile_map->end()) {
497    // The synced profile already exists locally.  It might need to be updated.
498    if (OverwriteProfileWithServerData(
499            autofill_specifics, existing_profile->second, app_locale_)) {
500      bundle->profiles_to_update.push_back(existing_profile->second);
501    }
502    return existing_profile;
503  }
504
505
506  // New profile synced.
507  AutofillProfile* new_profile = new AutofillProfile(
508      autofill_specifics.guid(), autofill_specifics.origin());
509  OverwriteProfileWithServerData(autofill_specifics, new_profile, app_locale_);
510
511  // Check if profile appears under a different guid. Compares only profile
512  // contents. (Ignores origin and language code in comparison.)
513  //
514  // Unverified profiles should never overwrite verified ones.
515  for (GUIDToProfileMap::iterator it = profile_map->begin();
516       it != profile_map->end(); ++it) {
517    AutofillProfile* local_profile = it->second;
518    if (local_profile->Compare(*new_profile) == 0) {
519      // Ensure that a verified profile can never revert back to an unverified
520      // one.
521      if (local_profile->IsVerified() && !new_profile->IsVerified()) {
522        new_profile->set_origin(local_profile->origin());
523        bundle->profiles_to_sync_back.push_back(new_profile);
524      }
525
526      bundle->profiles_to_delete.push_back(local_profile->guid());
527      DVLOG(2) << "[AUTOFILL SYNC]"
528               << "Found in sync db but with a different guid: "
529               << UTF16ToUTF8(local_profile->GetRawInfo(NAME_FIRST))
530               << UTF16ToUTF8(local_profile->GetRawInfo(NAME_LAST))
531               << "New guid " << new_profile->guid()
532               << ". Profile to be deleted " << local_profile->guid();
533      profile_map->erase(it);
534      break;
535    } else if (!local_profile->IsVerified() &&
536               !new_profile->IsVerified() &&
537               !local_profile->PrimaryValue().empty() &&
538               local_profile->PrimaryValue() == new_profile->PrimaryValue()) {
539      // Add it to candidates for merge - if there is no profile with this
540      // guid we will merge them.
541      bundle->candidates_to_merge.insert(
542          std::make_pair(local_profile->guid(), new_profile));
543    }
544  }
545  profiles_.push_back(new_profile);
546  bundle->profiles_to_add.push_back(new_profile);
547  return profile_map->insert(std::make_pair(new_profile->guid(),
548                                            new_profile)).first;
549}
550
551void AutofillProfileSyncableService::ActOnChange(
552     const AutofillProfileChange& change) {
553  DCHECK((change.type() == AutofillProfileChange::REMOVE &&
554          !change.profile()) ||
555         (change.type() != AutofillProfileChange::REMOVE && change.profile()));
556  DCHECK(sync_processor_.get());
557  syncer::SyncChangeList new_changes;
558  DataBundle bundle;
559  switch (change.type()) {
560    case AutofillProfileChange::ADD:
561      new_changes.push_back(
562          syncer::SyncChange(FROM_HERE,
563                             syncer::SyncChange::ACTION_ADD,
564                             CreateData(*(change.profile()))));
565      DCHECK(profiles_map_.find(change.profile()->guid()) ==
566             profiles_map_.end());
567      profiles_.push_back(new AutofillProfile(*(change.profile())));
568      profiles_map_[change.profile()->guid()] = profiles_.get().back();
569      break;
570    case AutofillProfileChange::UPDATE: {
571      GUIDToProfileMap::iterator it = profiles_map_.find(
572          change.profile()->guid());
573      DCHECK(it != profiles_map_.end());
574      *(it->second) = *(change.profile());
575      new_changes.push_back(
576          syncer::SyncChange(FROM_HERE,
577                             syncer::SyncChange::ACTION_UPDATE,
578                             CreateData(*(change.profile()))));
579      break;
580    }
581    case AutofillProfileChange::REMOVE: {
582      AutofillProfile empty_profile(change.key(), std::string());
583      new_changes.push_back(
584          syncer::SyncChange(FROM_HERE,
585                             syncer::SyncChange::ACTION_DELETE,
586                             CreateData(empty_profile)));
587      profiles_map_.erase(change.key());
588      break;
589    }
590    default:
591      NOTREACHED();
592  }
593  syncer::SyncError error =
594      sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
595  if (error.IsSet()) {
596    // TODO(isherman): Investigating http://crbug.com/121592
597    VLOG(1) << "[AUTOFILL SYNC] "
598            << "Failed processing change:\n"
599            << "  Error: " << error.message() << "\n"
600            << "  Guid: " << change.key();
601  }
602}
603
604syncer::SyncData AutofillProfileSyncableService::CreateData(
605    const AutofillProfile& profile) {
606  sync_pb::EntitySpecifics specifics;
607  WriteAutofillProfile(profile, &specifics);
608  return
609      syncer::SyncData::CreateLocalData(
610          profile.guid(), profile.guid(), specifics);
611}
612
613bool AutofillProfileSyncableService::UpdateField(
614    ServerFieldType field_type,
615    const std::string& new_value,
616    AutofillProfile* autofill_profile) {
617  if (UTF16ToUTF8(autofill_profile->GetRawInfo(field_type)) == new_value)
618    return false;
619  autofill_profile->SetRawInfo(field_type, UTF8ToUTF16(new_value));
620  return true;
621}
622
623bool AutofillProfileSyncableService::UpdateMultivaluedField(
624    ServerFieldType field_type,
625    const ::google::protobuf::RepeatedPtrField<std::string>& new_values,
626    AutofillProfile* autofill_profile) {
627  std::vector<base::string16> values;
628  autofill_profile->GetRawMultiInfo(field_type, &values);
629  bool changed = false;
630  if (static_cast<size_t>(new_values.size()) != values.size()) {
631    values.clear();
632    values.resize(static_cast<size_t>(new_values.size()));
633    changed = true;
634  }
635  for (size_t i = 0; i < values.size(); ++i) {
636    base::string16 synced_value(
637        UTF8ToUTF16(new_values.Get(static_cast<int>(i))));
638    if (values[i] != synced_value) {
639      values[i] = synced_value;
640      changed = true;
641    }
642  }
643  if (changed)
644    autofill_profile->SetRawMultiInfo(field_type, values);
645  return changed;
646}
647
648bool AutofillProfileSyncableService::MergeProfile(
649    const AutofillProfile& merge_from,
650    AutofillProfile* merge_into,
651    const std::string& app_locale) {
652  // Overwrites all single values and adds to mutli-values. Does not overwrite
653  // GUID.
654  merge_into->OverwriteWithOrAddTo(merge_from, app_locale);
655  return !merge_into->EqualsSansGuid(merge_from);
656}
657
658AutofillTable* AutofillProfileSyncableService::GetAutofillTable() const {
659  return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase());
660}
661
662void AutofillProfileSyncableService::InjectStartSyncFlare(
663    const syncer::SyncableService::StartSyncFlare& flare) {
664  flare_ = flare;
665}
666
667AutofillProfileSyncableService::DataBundle::DataBundle() {}
668
669AutofillProfileSyncableService::DataBundle::~DataBundle() {}
670
671}  // namespace autofill
672