Home | History | Annotate | Download | only in webdata
      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   // 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
    396 void 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 
    471 void 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 
    480 AutofillProfileSyncableService::GUIDToProfileMap::iterator
    481 AutofillProfileSyncableService::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 
    551 void 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 
    604 syncer::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 
    613 bool 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 
    623 bool 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 
    648 bool 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 
    658 AutofillTable* AutofillProfileSyncableService::GetAutofillTable() const {
    659   return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase());
    660 }
    661 
    662 void AutofillProfileSyncableService::InjectStartSyncFlare(
    663     const syncer::SyncableService::StartSyncFlare& flare) {
    664   flare_ = flare;
    665 }
    666 
    667 AutofillProfileSyncableService::DataBundle::DataBundle() {}
    668 
    669 AutofillProfileSyncableService::DataBundle::~DataBundle() {}
    670 
    671 }  // namespace autofill
    672