Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / components / autofill / core / browser / webdata / autofill_profile_syncable_service.cc
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
21 using base::ASCIIToUTF16;
22 using base::UTF8ToUTF16;
23 using base::UTF16ToUTF8;
24
25 namespace autofill {
26
27 namespace {
28
29 std::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
36 void* 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
45 const char kAutofillProfileTag[] = "google_chrome_autofill_profiles";
46
47 AutofillProfileSyncableService::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
58 AutofillProfileSyncableService::~AutofillProfileSyncableService() {
59   DCHECK(CalledOnValidThread());
60 }
61
62 // static
63 void 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
73 AutofillProfileSyncableService*
74 AutofillProfileSyncableService::FromWebDataService(
75     AutofillWebDataService* web_data_service) {
76   return static_cast<AutofillProfileSyncableService*>(
77       web_data_service->GetDBUserData()->GetUserData(UserDataKey()));
78 }
79
80 AutofillProfileSyncableService::AutofillProfileSyncableService()
81     : webdata_backend_(NULL),
82       scoped_observer_(this) {
83 }
84
85 syncer::SyncMergeResult
86 AutofillProfileSyncableService::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
196 void 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
206 syncer::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
221 syncer::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
270 void 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
284 bool AutofillProfileSyncableService::LoadAutofillData(
285     std::vector<AutofillProfile*>* profiles) {
286   return GetAutofillTable()->GetAutofillProfiles(profiles);
287 }
288
289 bool 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
314 bool 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   diff = UpdateMultivaluedField(EMAIL_ADDRESS,
336                                 specifics.email_address(), profile) || diff;
337   diff = UpdateMultivaluedField(PHONE_HOME_WHOLE_NUMBER,
338                                 specifics.phone_home_whole_number(),
339                                 profile) || diff;
340
341   // Update all simple single-valued address fields.
342   diff = UpdateField(COMPANY_NAME, specifics.company_name(), profile) || diff;
343   diff = UpdateField(ADDRESS_HOME_CITY,
344                      specifics.address_home_city(), profile) || diff;
345   diff = UpdateField(ADDRESS_HOME_STATE,
346                      specifics.address_home_state(), profile) || diff;
347   diff = UpdateField(ADDRESS_HOME_ZIP,
348                      specifics.address_home_zip(), profile) || diff;
349   diff = UpdateField(ADDRESS_HOME_SORTING_CODE,
350                      specifics.address_home_sorting_code(), profile) || diff;
351   diff = UpdateField(ADDRESS_HOME_DEPENDENT_LOCALITY,
352                      specifics.address_home_dependent_locality(),
353                      profile) || diff;
354
355   // Update the country field, which can contain either a country code (if set
356   // by a newer version of Chrome), or a country name (if set by an older
357   // version of Chrome).
358   base::string16 country_name_or_code =
359       ASCIIToUTF16(specifics.address_home_country());
360   std::string country_code =
361       AutofillCountry::GetCountryCode(country_name_or_code, app_locale);
362   diff = UpdateField(ADDRESS_HOME_COUNTRY, country_code, profile) || diff;
363
364   // Update the street address.  In newer versions of Chrome (M34+), this data
365   // is stored in the |address_home_street_address| field.  In older versions,
366   // this data is stored separated out by address line.
367   if (specifics.has_address_home_street_address()) {
368     diff = UpdateField(ADDRESS_HOME_STREET_ADDRESS,
369                        specifics.address_home_street_address(),
370                        profile) || diff;
371   } else {
372     diff = UpdateField(ADDRESS_HOME_LINE1,
373                        specifics.address_home_line1(), profile) || diff;
374     diff = UpdateField(ADDRESS_HOME_LINE2,
375                        specifics.address_home_line2(), profile) || diff;
376   }
377
378   // Update the BCP 47 language code that can be used to format the address for
379   // display.
380   if (specifics.has_address_home_language_code() &&
381       specifics.address_home_language_code() != profile->language_code()) {
382     profile->set_language_code(specifics.address_home_language_code());
383     diff = true;
384   }
385
386   return diff;
387 }
388
389 // static
390 void AutofillProfileSyncableService::WriteAutofillProfile(
391     const AutofillProfile& profile,
392     sync_pb::EntitySpecifics* profile_specifics) {
393   sync_pb::AutofillProfileSpecifics* specifics =
394       profile_specifics->mutable_autofill_profile();
395
396   DCHECK(base::IsValidGUID(profile.guid()));
397
398   // Reset all multi-valued fields in the protobuf.
399   specifics->clear_name_first();
400   specifics->clear_name_middle();
401   specifics->clear_name_last();
402   specifics->clear_email_address();
403   specifics->clear_phone_home_whole_number();
404
405   specifics->set_guid(profile.guid());
406   specifics->set_origin(profile.origin());
407
408   std::vector<base::string16> values;
409   profile.GetRawMultiInfo(NAME_FIRST, &values);
410   for (size_t i = 0; i < values.size(); ++i) {
411     specifics->add_name_first(LimitData(UTF16ToUTF8(values[i])));
412   }
413
414   profile.GetRawMultiInfo(NAME_MIDDLE, &values);
415   for (size_t i = 0; i < values.size(); ++i) {
416     specifics->add_name_middle(LimitData(UTF16ToUTF8(values[i])));
417   }
418
419   profile.GetRawMultiInfo(NAME_LAST, &values);
420   for (size_t i = 0; i < values.size(); ++i) {
421     specifics->add_name_last(LimitData(UTF16ToUTF8(values[i])));
422   }
423
424   specifics->set_address_home_line1(
425       LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))));
426   specifics->set_address_home_line2(
427       LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))));
428   specifics->set_address_home_city(
429       LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))));
430   specifics->set_address_home_state(
431       LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))));
432   specifics->set_address_home_zip(
433       LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))));
434   specifics->set_address_home_country(
435       LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))));
436   specifics->set_address_home_street_address(
437       LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS))));
438   specifics->set_address_home_sorting_code(
439       LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE))));
440   specifics->set_address_home_dependent_locality(
441       LimitData(
442           UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))));
443   specifics->set_address_home_language_code(LimitData(profile.language_code()));
444
445   profile.GetRawMultiInfo(EMAIL_ADDRESS, &values);
446   for (size_t i = 0; i < values.size(); ++i) {
447     specifics->add_email_address(LimitData(UTF16ToUTF8(values[i])));
448   }
449
450   specifics->set_company_name(
451       LimitData(UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))));
452
453   profile.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
454   for (size_t i = 0; i < values.size(); ++i) {
455     specifics->add_phone_home_whole_number(LimitData(UTF16ToUTF8(values[i])));
456   }
457 }
458
459 void AutofillProfileSyncableService::CreateGUIDToProfileMap(
460     const std::vector<AutofillProfile*>& profiles,
461     GUIDToProfileMap* profile_map) {
462   DCHECK(profile_map);
463   profile_map->clear();
464   for (size_t i = 0; i < profiles.size(); ++i)
465     (*profile_map)[profiles[i]->guid()] = profiles[i];
466 }
467
468 AutofillProfileSyncableService::GUIDToProfileMap::iterator
469 AutofillProfileSyncableService::CreateOrUpdateProfile(
470     const syncer::SyncData& data,
471     GUIDToProfileMap* profile_map,
472     DataBundle* bundle) {
473   DCHECK(profile_map);
474   DCHECK(bundle);
475
476   DCHECK_EQ(syncer::AUTOFILL_PROFILE, data.GetDataType());
477
478   const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
479   const sync_pb::AutofillProfileSpecifics& autofill_specifics(
480       specifics.autofill_profile());
481
482   GUIDToProfileMap::iterator existing_profile = profile_map->find(
483         autofill_specifics.guid());
484   if (existing_profile != profile_map->end()) {
485     // The synced profile already exists locally.  It might need to be updated.
486     if (OverwriteProfileWithServerData(
487             autofill_specifics, existing_profile->second, app_locale_)) {
488       bundle->profiles_to_update.push_back(existing_profile->second);
489     }
490     return existing_profile;
491   }
492
493
494   // New profile synced.
495   AutofillProfile* new_profile = new AutofillProfile(
496       autofill_specifics.guid(), autofill_specifics.origin());
497   OverwriteProfileWithServerData(autofill_specifics, new_profile, app_locale_);
498
499   // Check if profile appears under a different guid. Compares only profile
500   // contents. (Ignores origin and language code in comparison.)
501   //
502   // Unverified profiles should never overwrite verified ones.
503   for (GUIDToProfileMap::iterator it = profile_map->begin();
504        it != profile_map->end(); ++it) {
505     AutofillProfile* local_profile = it->second;
506     if (local_profile->Compare(*new_profile) == 0) {
507       // Ensure that a verified profile can never revert back to an unverified
508       // one.
509       if (local_profile->IsVerified() && !new_profile->IsVerified()) {
510         new_profile->set_origin(local_profile->origin());
511         bundle->profiles_to_sync_back.push_back(new_profile);
512       }
513
514       bundle->profiles_to_delete.push_back(local_profile->guid());
515       DVLOG(2) << "[AUTOFILL SYNC]"
516                << "Found in sync db but with a different guid: "
517                << UTF16ToUTF8(local_profile->GetRawInfo(NAME_FIRST))
518                << UTF16ToUTF8(local_profile->GetRawInfo(NAME_LAST))
519                << "New guid " << new_profile->guid()
520                << ". Profile to be deleted " << local_profile->guid();
521       profile_map->erase(it);
522       break;
523     } else if (!local_profile->IsVerified() &&
524                !new_profile->IsVerified() &&
525                !local_profile->PrimaryValue().empty() &&
526                local_profile->PrimaryValue() == new_profile->PrimaryValue()) {
527       // Add it to candidates for merge - if there is no profile with this
528       // guid we will merge them.
529       bundle->candidates_to_merge.insert(
530           std::make_pair(local_profile->guid(), new_profile));
531     }
532   }
533   profiles_.push_back(new_profile);
534   bundle->profiles_to_add.push_back(new_profile);
535   return profile_map->insert(std::make_pair(new_profile->guid(),
536                                             new_profile)).first;
537 }
538
539 void AutofillProfileSyncableService::ActOnChange(
540      const AutofillProfileChange& change) {
541   DCHECK((change.type() == AutofillProfileChange::REMOVE &&
542           !change.profile()) ||
543          (change.type() != AutofillProfileChange::REMOVE && change.profile()));
544   DCHECK(sync_processor_.get());
545   syncer::SyncChangeList new_changes;
546   DataBundle bundle;
547   switch (change.type()) {
548     case AutofillProfileChange::ADD:
549       new_changes.push_back(
550           syncer::SyncChange(FROM_HERE,
551                              syncer::SyncChange::ACTION_ADD,
552                              CreateData(*(change.profile()))));
553       DCHECK(profiles_map_.find(change.profile()->guid()) ==
554              profiles_map_.end());
555       profiles_.push_back(new AutofillProfile(*(change.profile())));
556       profiles_map_[change.profile()->guid()] = profiles_.get().back();
557       break;
558     case AutofillProfileChange::UPDATE: {
559       GUIDToProfileMap::iterator it = profiles_map_.find(
560           change.profile()->guid());
561       DCHECK(it != profiles_map_.end());
562       *(it->second) = *(change.profile());
563       new_changes.push_back(
564           syncer::SyncChange(FROM_HERE,
565                              syncer::SyncChange::ACTION_UPDATE,
566                              CreateData(*(change.profile()))));
567       break;
568     }
569     case AutofillProfileChange::REMOVE: {
570       AutofillProfile empty_profile(change.key(), std::string());
571       new_changes.push_back(
572           syncer::SyncChange(FROM_HERE,
573                              syncer::SyncChange::ACTION_DELETE,
574                              CreateData(empty_profile)));
575       profiles_map_.erase(change.key());
576       break;
577     }
578     default:
579       NOTREACHED();
580   }
581   syncer::SyncError error =
582       sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
583   if (error.IsSet()) {
584     // TODO(isherman): Investigating http://crbug.com/121592
585     VLOG(1) << "[AUTOFILL SYNC] "
586             << "Failed processing change:\n"
587             << "  Error: " << error.message() << "\n"
588             << "  Guid: " << change.key();
589   }
590 }
591
592 syncer::SyncData AutofillProfileSyncableService::CreateData(
593     const AutofillProfile& profile) {
594   sync_pb::EntitySpecifics specifics;
595   WriteAutofillProfile(profile, &specifics);
596   return
597       syncer::SyncData::CreateLocalData(
598           profile.guid(), profile.guid(), specifics);
599 }
600
601 bool AutofillProfileSyncableService::UpdateField(
602     ServerFieldType field_type,
603     const std::string& new_value,
604     AutofillProfile* autofill_profile) {
605   if (UTF16ToUTF8(autofill_profile->GetRawInfo(field_type)) == new_value)
606     return false;
607   autofill_profile->SetRawInfo(field_type, UTF8ToUTF16(new_value));
608   return true;
609 }
610
611 bool AutofillProfileSyncableService::UpdateMultivaluedField(
612     ServerFieldType field_type,
613     const ::google::protobuf::RepeatedPtrField<std::string>& new_values,
614     AutofillProfile* autofill_profile) {
615   std::vector<base::string16> values;
616   autofill_profile->GetRawMultiInfo(field_type, &values);
617   bool changed = false;
618   if (static_cast<size_t>(new_values.size()) != values.size()) {
619     values.clear();
620     values.resize(static_cast<size_t>(new_values.size()));
621     changed = true;
622   }
623   for (size_t i = 0; i < values.size(); ++i) {
624     base::string16 synced_value(
625         UTF8ToUTF16(new_values.Get(static_cast<int>(i))));
626     if (values[i] != synced_value) {
627       values[i] = synced_value;
628       changed = true;
629     }
630   }
631   if (changed)
632     autofill_profile->SetRawMultiInfo(field_type, values);
633   return changed;
634 }
635
636 bool AutofillProfileSyncableService::MergeProfile(
637     const AutofillProfile& merge_from,
638     AutofillProfile* merge_into,
639     const std::string& app_locale) {
640   // Overwrites all single values and adds to mutli-values. Does not overwrite
641   // GUID.
642   merge_into->OverwriteWithOrAddTo(merge_from, app_locale);
643   return !merge_into->EqualsSansGuid(merge_from);
644 }
645
646 AutofillTable* AutofillProfileSyncableService::GetAutofillTable() const {
647   return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase());
648 }
649
650 void AutofillProfileSyncableService::InjectStartSyncFlare(
651     const syncer::SyncableService::StartSyncFlare& flare) {
652   flare_ = flare;
653 }
654
655 AutofillProfileSyncableService::DataBundle::DataBundle() {}
656
657 AutofillProfileSyncableService::DataBundle::~DataBundle() {}
658
659 }  // namespace autofill