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 #ifndef CHROME_BROWSER_WEBDATA_AUTOFILL_PROFILE_SYNCABLE_SERVICE_H_ 5 #define CHROME_BROWSER_WEBDATA_AUTOFILL_PROFILE_SYNCABLE_SERVICE_H_ 6 7 #include <map> 8 #include <string> 9 #include <vector> 10 11 #include "base/basictypes.h" 12 #include "base/memory/scoped_vector.h" 13 #include "base/scoped_observer.h" 14 #include "base/supports_user_data.h" 15 #include "base/synchronization/lock.h" 16 #include "base/threading/non_thread_safe.h" 17 #include "components/autofill/core/browser/field_types.h" 18 #include "components/autofill/core/browser/webdata/autofill_change.h" 19 #include "components/autofill/core/browser/webdata/autofill_entry.h" 20 #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" 21 #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h" 22 #include "sync/api/sync_change.h" 23 #include "sync/api/sync_data.h" 24 #include "sync/api/sync_error.h" 25 #include "sync/api/syncable_service.h" 26 #include "sync/protocol/autofill_specifics.pb.h" 27 28 class ProfileSyncServiceAutofillTest; 29 class WebDataServiceBase; 30 31 namespace autofill { 32 class AutofillProfile; 33 class AutofillTable; 34 class AutofillWebDataService; 35 class FormGroup; 36 } // namespace autofill 37 38 extern const char kAutofillProfileTag[]; 39 40 // The sync implementation for AutofillProfiles. 41 // MergeDataAndStartSyncing() called first, it does cloud->local and 42 // local->cloud syncs. Then for each cloud change we receive 43 // ProcessSyncChanges() and for each local change Observe() is called. 44 class AutofillProfileSyncableService 45 : public base::SupportsUserData::Data, 46 public syncer::SyncableService, 47 public autofill::AutofillWebDataServiceObserverOnDBThread, 48 public base::NonThreadSafe { 49 public: 50 virtual ~AutofillProfileSyncableService(); 51 52 // Creates a new AutofillProfileSyncableService and hangs it off of 53 // |web_data_service|, which takes ownership. 54 static void CreateForWebDataServiceAndBackend( 55 autofill::AutofillWebDataService* web_data_service, 56 autofill::AutofillWebDataBackend* webdata_backend, 57 const std::string& app_locale); 58 59 // Retrieves the AutofillProfileSyncableService stored on |web_data_service|. 60 static AutofillProfileSyncableService* FromWebDataService( 61 autofill::AutofillWebDataService* web_data_service); 62 63 static syncer::ModelType model_type() { return syncer::AUTOFILL_PROFILE; } 64 65 // syncer::SyncableService implementation. 66 virtual syncer::SyncMergeResult MergeDataAndStartSyncing( 67 syncer::ModelType type, 68 const syncer::SyncDataList& initial_sync_data, 69 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 70 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) OVERRIDE; 71 virtual void StopSyncing(syncer::ModelType type) OVERRIDE; 72 virtual syncer::SyncDataList GetAllSyncData( 73 syncer::ModelType type) const OVERRIDE; 74 virtual syncer::SyncError ProcessSyncChanges( 75 const tracked_objects::Location& from_here, 76 const syncer::SyncChangeList& change_list) OVERRIDE; 77 78 // AutofillWebDataServiceObserverOnDBThread implementation. 79 virtual void AutofillProfileChanged( 80 const autofill::AutofillProfileChange& change) OVERRIDE; 81 82 // Provides a StartSyncFlare to the SyncableService. See 83 // sync_start_util for more. 84 void InjectStartSyncFlare( 85 const syncer::SyncableService::StartSyncFlare& flare); 86 87 protected: 88 AutofillProfileSyncableService( 89 autofill::AutofillWebDataBackend* webdata_backend, 90 const std::string& app_locale); 91 92 // A convenience wrapper of a bunch of state we pass around while 93 // associating models, and send to the WebDatabase for persistence. 94 // We do this so we hold the write lock for only a small period. 95 // When storing the web db we are out of the write lock. 96 struct DataBundle; 97 98 // Helper to query WebDatabase for the current autofill state. 99 // Made virtual for ease of mocking in unit tests. 100 // Caller owns returned |profiles|. 101 virtual bool LoadAutofillData( 102 std::vector<autofill::AutofillProfile*>* profiles); 103 104 // Helper to persist any changes that occured during model association to 105 // the WebDatabase. 106 // Made virtual for ease of mocking in unit tests. 107 virtual bool SaveChangesToWebData(const DataBundle& bundle); 108 109 // For unit tests. 110 AutofillProfileSyncableService(); 111 void set_sync_processor(syncer::SyncChangeProcessor* sync_processor) { 112 sync_processor_.reset(sync_processor); 113 } 114 115 // Creates syncer::SyncData based on supplied |profile|. 116 // Exposed for unit tests. 117 static syncer::SyncData CreateData(const autofill::AutofillProfile& profile); 118 119 private: 120 friend class ProfileSyncServiceAutofillTest; 121 FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, 122 UpdateField); 123 FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, 124 UpdateMultivaluedField); 125 FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, 126 MergeProfile); 127 128 // The map of the guid to profiles owned by the |profiles_| vector. 129 typedef std::map<std::string, autofill::AutofillProfile*> GUIDToProfileMap; 130 131 // Helper function that overwrites |profile| with data from proto-buffer 132 // |specifics|. 133 static bool OverwriteProfileWithServerData( 134 const sync_pb::AutofillProfileSpecifics& specifics, 135 autofill::AutofillProfile* profile, 136 const std::string& app_locale); 137 138 // Writes |profile| data into supplied |profile_specifics|. 139 static void WriteAutofillProfile(const autofill::AutofillProfile& profile, 140 sync_pb::EntitySpecifics* profile_specifics); 141 142 // Creates |profile_map| from the supplied |profiles| vector. Necessary for 143 // fast processing of the changes. 144 void CreateGUIDToProfileMap( 145 const std::vector<autofill::AutofillProfile*>& profiles, 146 GUIDToProfileMap* profile_map); 147 148 // Creates or updates a profile based on |data|. Looks at the guid of the data 149 // and if a profile with such guid is present in |profile_map| updates it. If 150 // not, searches through it for similar profiles. If similar profile is 151 // found substitutes it for the new one, otherwise adds a new profile. Returns 152 // iterator pointing to added/updated profile. 153 GUIDToProfileMap::iterator CreateOrUpdateProfile( 154 const syncer::SyncData& data, 155 GUIDToProfileMap* profile_map, 156 DataBundle* bundle); 157 158 // Syncs |change| to the cloud. 159 void ActOnChange(const autofill::AutofillProfileChange& change); 160 161 autofill::AutofillTable* GetAutofillTable() const; 162 163 // Helper to compare the local value and cloud value of a field, copy into 164 // the local value if they differ, and return whether the change happened. 165 static bool UpdateField(autofill::ServerFieldType field_type, 166 const std::string& new_value, 167 autofill::AutofillProfile* autofill_profile); 168 // The same as |UpdateField|, but for multi-valued fields. 169 static bool UpdateMultivaluedField( 170 autofill::ServerFieldType field_type, 171 const ::google::protobuf::RepeatedPtrField<std::string>& new_value, 172 autofill::AutofillProfile* autofill_profile); 173 174 // Calls merge_into->OverwriteWithOrAddTo() and then checks if the 175 // |merge_into| has extra data. Returns |true| if |merge_into| posseses some 176 // multi-valued field values that are not in |merge_from| or if the origins 177 // of the two profiles differ, false otherwise. 178 // TODO(isherman): Seems like this should return |true| if |merge_into| was 179 // modified at all: http://crbug.com/248440 180 static bool MergeProfile(const autofill::AutofillProfile& merge_from, 181 autofill::AutofillProfile* merge_into, 182 const std::string& app_locale); 183 184 autofill::AutofillWebDataBackend* webdata_backend_; // WEAK 185 std::string app_locale_; 186 ScopedObserver<autofill::AutofillWebDataBackend, 187 AutofillProfileSyncableService> scoped_observer_; 188 189 // Cached Autofill profiles. *Warning* deleted profiles are still in the 190 // vector - use the |profiles_map_| to iterate through actual profiles. 191 ScopedVector<autofill::AutofillProfile> profiles_; 192 GUIDToProfileMap profiles_map_; 193 194 scoped_ptr<syncer::SyncChangeProcessor> sync_processor_; 195 196 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory_; 197 198 syncer::SyncableService::StartSyncFlare flare_; 199 200 DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncableService); 201 }; 202 203 // This object is used in unit tests as well, so it defined here. 204 struct AutofillProfileSyncableService::DataBundle { 205 DataBundle(); 206 ~DataBundle(); 207 208 std::vector<std::string> profiles_to_delete; 209 std::vector<autofill::AutofillProfile*> profiles_to_update; 210 std::vector<autofill::AutofillProfile*> profiles_to_add; 211 212 // When we go through sync we find profiles that are similar but unmatched. 213 // Merge such profiles. 214 GUIDToProfileMap candidates_to_merge; 215 // Profiles that have multi-valued fields that are not in sync. 216 std::vector<autofill::AutofillProfile*> profiles_to_sync_back; 217 }; 218 219 #endif // CHROME_BROWSER_WEBDATA_AUTOFILL_PROFILE_SYNCABLE_SERVICE_H_ 220