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