autofill_profile_syncable_service.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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 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 390void 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 459void 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 468AutofillProfileSyncableService::GUIDToProfileMap::iterator 469AutofillProfileSyncableService::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 539void 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 592syncer::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 601bool 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 611bool 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 636bool 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 646AutofillTable* AutofillProfileSyncableService::GetAutofillTable() const { 647 return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase()); 648} 649 650void AutofillProfileSyncableService::InjectStartSyncFlare( 651 const syncer::SyncableService::StartSyncFlare& flare) { 652 flare_ = flare; 653} 654 655AutofillProfileSyncableService::DataBundle::DataBundle() {} 656 657AutofillProfileSyncableService::DataBundle::~DataBundle() {} 658 659} // namespace autofill 660