| OLD | NEW |
| (Empty) |
| 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 "chrome/browser/sync/glue/device_info_sync_service.h" | |
| 6 | |
| 7 #include "base/strings/stringprintf.h" | |
| 8 #include "chrome/browser/sync/glue/local_device_info_provider.h" | |
| 9 #include "sync/api/sync_change.h" | |
| 10 #include "sync/protocol/sync.pb.h" | |
| 11 #include "sync/util/time.h" | |
| 12 | |
| 13 namespace browser_sync { | |
| 14 | |
| 15 using syncer::ModelType; | |
| 16 using syncer::SyncChange; | |
| 17 using syncer::SyncChangeList; | |
| 18 using syncer::SyncChangeProcessor; | |
| 19 using syncer::SyncData; | |
| 20 using syncer::SyncDataList; | |
| 21 using syncer::SyncErrorFactory; | |
| 22 using syncer::SyncMergeResult; | |
| 23 | |
| 24 DeviceInfoSyncService::DeviceInfoSyncService( | |
| 25 LocalDeviceInfoProvider* local_device_info_provider) | |
| 26 : local_device_backup_time_(-1), | |
| 27 local_device_info_provider_(local_device_info_provider) { | |
| 28 DCHECK(local_device_info_provider); | |
| 29 } | |
| 30 | |
| 31 DeviceInfoSyncService::~DeviceInfoSyncService() { | |
| 32 } | |
| 33 | |
| 34 SyncMergeResult DeviceInfoSyncService::MergeDataAndStartSyncing( | |
| 35 ModelType type, | |
| 36 const SyncDataList& initial_sync_data, | |
| 37 scoped_ptr<SyncChangeProcessor> sync_processor, | |
| 38 scoped_ptr<SyncErrorFactory> error_handler) { | |
| 39 DCHECK(sync_processor.get()); | |
| 40 DCHECK(error_handler.get()); | |
| 41 DCHECK_EQ(type, syncer::DEVICE_INFO); | |
| 42 | |
| 43 DCHECK(all_data_.empty()); | |
| 44 | |
| 45 sync_processor_ = sync_processor.Pass(); | |
| 46 error_handler_ = error_handler.Pass(); | |
| 47 | |
| 48 // Initialization should be completed before this type is enabled | |
| 49 // and local device info must be available. | |
| 50 const DeviceInfo* local_device_info = | |
| 51 local_device_info_provider_->GetLocalDeviceInfo(); | |
| 52 DCHECK(local_device_info != NULL); | |
| 53 | |
| 54 // Indicates whether a local device has been added or updated. | |
| 55 // |change_type| defaults to ADD and might be changed to | |
| 56 // UPDATE to INVALID down below if the initial data contains | |
| 57 // data matching the local device ID. | |
| 58 SyncChange::SyncChangeType change_type = SyncChange::ACTION_ADD; | |
| 59 size_t num_items_new = 0; | |
| 60 size_t num_items_updated = 0; | |
| 61 | |
| 62 // Iterate over all initial sync data and copy it to the cache. | |
| 63 for (SyncDataList::const_iterator iter = initial_sync_data.begin(); | |
| 64 iter != initial_sync_data.end(); | |
| 65 ++iter) { | |
| 66 DCHECK_EQ(syncer::DEVICE_INFO, iter->GetDataType()); | |
| 67 | |
| 68 const std::string& id = iter->GetSpecifics().device_info().cache_guid(); | |
| 69 | |
| 70 if (id == local_device_info->guid()) { | |
| 71 // |initial_sync_data| contains data matching the local device. | |
| 72 scoped_ptr<DeviceInfo> synced_local_device_info = | |
| 73 make_scoped_ptr(CreateDeviceInfo(*iter)); | |
| 74 | |
| 75 // Retrieve local device backup timestamp value from the sync data. | |
| 76 bool has_synced_backup_time = | |
| 77 iter->GetSpecifics().device_info().has_backup_timestamp(); | |
| 78 int64 synced_backup_time = | |
| 79 has_synced_backup_time | |
| 80 ? iter->GetSpecifics().device_info().backup_timestamp() | |
| 81 : -1; | |
| 82 | |
| 83 // Overwrite |local_device_backup_time_| with this value if it | |
| 84 // hasn't been set yet. | |
| 85 if (!has_local_device_backup_time() && has_synced_backup_time) { | |
| 86 set_local_device_backup_time(synced_backup_time); | |
| 87 } | |
| 88 | |
| 89 // Store the synced device info for the local device only | |
| 90 // it is the same as the local info. Otherwise store the local | |
| 91 // device info and issue a change further below after finishing | |
| 92 // processing the |initial_sync_data|. | |
| 93 if (synced_local_device_info->Equals(*local_device_info) && | |
| 94 synced_backup_time == local_device_backup_time()) { | |
| 95 change_type = SyncChange::ACTION_INVALID; | |
| 96 } else { | |
| 97 num_items_updated++; | |
| 98 change_type = SyncChange::ACTION_UPDATE; | |
| 99 continue; | |
| 100 } | |
| 101 } else { | |
| 102 // A new device that doesn't match the local device. | |
| 103 num_items_new++; | |
| 104 } | |
| 105 | |
| 106 StoreSyncData(id, *iter); | |
| 107 } | |
| 108 | |
| 109 syncer::SyncMergeResult result(type); | |
| 110 | |
| 111 // Add SyncData for the local device if it is new or different than | |
| 112 // the synced one, and also add it to the |change_list|. | |
| 113 if (change_type != SyncChange::ACTION_INVALID) { | |
| 114 SyncData local_data = CreateLocalData(local_device_info); | |
| 115 StoreSyncData(local_device_info->guid(), local_data); | |
| 116 | |
| 117 SyncChangeList change_list; | |
| 118 change_list.push_back(SyncChange(FROM_HERE, change_type, local_data)); | |
| 119 result.set_error( | |
| 120 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list)); | |
| 121 } | |
| 122 | |
| 123 result.set_num_items_before_association(1); | |
| 124 result.set_num_items_after_association(all_data_.size()); | |
| 125 result.set_num_items_added(num_items_new); | |
| 126 result.set_num_items_modified(num_items_updated); | |
| 127 result.set_num_items_deleted(0); | |
| 128 | |
| 129 NotifyObservers(); | |
| 130 | |
| 131 return result; | |
| 132 } | |
| 133 | |
| 134 void DeviceInfoSyncService::StopSyncing(syncer::ModelType type) { | |
| 135 all_data_.clear(); | |
| 136 sync_processor_.reset(); | |
| 137 error_handler_.reset(); | |
| 138 clear_local_device_backup_time(); | |
| 139 } | |
| 140 | |
| 141 SyncDataList DeviceInfoSyncService::GetAllSyncData( | |
| 142 syncer::ModelType type) const { | |
| 143 SyncDataList list; | |
| 144 | |
| 145 for (SyncDataMap::const_iterator iter = all_data_.begin(); | |
| 146 iter != all_data_.end(); | |
| 147 ++iter) { | |
| 148 list.push_back(iter->second); | |
| 149 } | |
| 150 | |
| 151 return list; | |
| 152 } | |
| 153 | |
| 154 syncer::SyncError DeviceInfoSyncService::ProcessSyncChanges( | |
| 155 const tracked_objects::Location& from_here, | |
| 156 const SyncChangeList& change_list) { | |
| 157 syncer::SyncError error; | |
| 158 | |
| 159 DCHECK(local_device_info_provider_->GetLocalDeviceInfo()); | |
| 160 const std::string& local_device_id = | |
| 161 local_device_info_provider_->GetLocalDeviceInfo()->guid(); | |
| 162 | |
| 163 bool has_changes = false; | |
| 164 | |
| 165 // Iterate over all chanages and merge entries. | |
| 166 for (SyncChangeList::const_iterator iter = change_list.begin(); | |
| 167 iter != change_list.end(); | |
| 168 ++iter) { | |
| 169 const SyncData& sync_data = iter->sync_data(); | |
| 170 DCHECK_EQ(syncer::DEVICE_INFO, sync_data.GetDataType()); | |
| 171 | |
| 172 const std::string& client_id = | |
| 173 sync_data.GetSpecifics().device_info().cache_guid(); | |
| 174 // Ignore device info matching the local device. | |
| 175 if (local_device_id == client_id) { | |
| 176 DVLOG(1) << "Ignoring sync changes for the local DEVICE_INFO"; | |
| 177 continue; | |
| 178 } | |
| 179 | |
| 180 if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) { | |
| 181 has_changes = true; | |
| 182 DeleteSyncData(client_id); | |
| 183 } else if (iter->change_type() == syncer::SyncChange::ACTION_UPDATE || | |
| 184 iter->change_type() == syncer::SyncChange::ACTION_ADD) { | |
| 185 has_changes = true; | |
| 186 StoreSyncData(client_id, sync_data); | |
| 187 } else { | |
| 188 error.Reset(FROM_HERE, "Invalid action received.", syncer::DEVICE_INFO); | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 if (has_changes) { | |
| 193 NotifyObservers(); | |
| 194 } | |
| 195 | |
| 196 return error; | |
| 197 } | |
| 198 | |
| 199 scoped_ptr<DeviceInfo> DeviceInfoSyncService::GetDeviceInfo( | |
| 200 const std::string& client_id) const { | |
| 201 SyncDataMap::const_iterator iter = all_data_.find(client_id); | |
| 202 if (iter == all_data_.end()) { | |
| 203 return scoped_ptr<DeviceInfo>(); | |
| 204 } | |
| 205 | |
| 206 return make_scoped_ptr(CreateDeviceInfo(iter->second)); | |
| 207 } | |
| 208 | |
| 209 ScopedVector<DeviceInfo> DeviceInfoSyncService::GetAllDeviceInfo() const { | |
| 210 ScopedVector<DeviceInfo> list; | |
| 211 | |
| 212 for (SyncDataMap::const_iterator iter = all_data_.begin(); | |
| 213 iter != all_data_.end(); | |
| 214 ++iter) { | |
| 215 list.push_back(CreateDeviceInfo(iter->second)); | |
| 216 } | |
| 217 | |
| 218 return list.Pass(); | |
| 219 } | |
| 220 | |
| 221 void DeviceInfoSyncService::AddObserver(Observer* observer) { | |
| 222 observers_.AddObserver(observer); | |
| 223 } | |
| 224 | |
| 225 void DeviceInfoSyncService::RemoveObserver(Observer* observer) { | |
| 226 observers_.RemoveObserver(observer); | |
| 227 } | |
| 228 | |
| 229 void DeviceInfoSyncService::NotifyObservers() { | |
| 230 FOR_EACH_OBSERVER(Observer, observers_, OnDeviceInfoChange()); | |
| 231 } | |
| 232 | |
| 233 void DeviceInfoSyncService::UpdateLocalDeviceBackupTime( | |
| 234 base::Time backup_time) { | |
| 235 set_local_device_backup_time(syncer::TimeToProtoTime(backup_time)); | |
| 236 | |
| 237 if (sync_processor_.get()) { | |
| 238 // Local device info must be available in advance | |
| 239 DCHECK(local_device_info_provider_->GetLocalDeviceInfo()); | |
| 240 const std::string& local_id = | |
| 241 local_device_info_provider_->GetLocalDeviceInfo()->guid(); | |
| 242 | |
| 243 SyncDataMap::iterator iter = all_data_.find(local_id); | |
| 244 DCHECK(iter != all_data_.end()); | |
| 245 | |
| 246 syncer::SyncData& data = iter->second; | |
| 247 if (UpdateBackupTime(&data)) { | |
| 248 // Local device backup time has changed. | |
| 249 // Push changes to the server via the |sync_processor_|. | |
| 250 SyncChangeList change_list; | |
| 251 change_list.push_back(SyncChange( | |
| 252 FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); | |
| 253 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list); | |
| 254 } | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 bool DeviceInfoSyncService::UpdateBackupTime(syncer::SyncData* sync_data) { | |
| 259 DCHECK(has_local_device_backup_time()); | |
| 260 DCHECK(sync_data->GetSpecifics().has_device_info()); | |
| 261 const sync_pb::DeviceInfoSpecifics& source_specifics = | |
| 262 sync_data->GetSpecifics().device_info(); | |
| 263 | |
| 264 if (!source_specifics.has_backup_timestamp() || | |
| 265 source_specifics.backup_timestamp() != local_device_backup_time()) { | |
| 266 sync_pb::EntitySpecifics entity(sync_data->GetSpecifics()); | |
| 267 entity.mutable_device_info()->set_backup_timestamp( | |
| 268 local_device_backup_time()); | |
| 269 *sync_data = CreateLocalData(entity); | |
| 270 | |
| 271 return true; | |
| 272 } | |
| 273 | |
| 274 return false; | |
| 275 } | |
| 276 | |
| 277 base::Time DeviceInfoSyncService::GetLocalDeviceBackupTime() const { | |
| 278 return has_local_device_backup_time() | |
| 279 ? syncer::ProtoTimeToTime(local_device_backup_time()) | |
| 280 : base::Time(); | |
| 281 } | |
| 282 | |
| 283 SyncData DeviceInfoSyncService::CreateLocalData(const DeviceInfo* info) { | |
| 284 sync_pb::EntitySpecifics entity; | |
| 285 sync_pb::DeviceInfoSpecifics& specifics = *entity.mutable_device_info(); | |
| 286 | |
| 287 specifics.set_cache_guid(info->guid()); | |
| 288 specifics.set_client_name(info->client_name()); | |
| 289 specifics.set_chrome_version(info->chrome_version()); | |
| 290 specifics.set_sync_user_agent(info->sync_user_agent()); | |
| 291 specifics.set_device_type(info->device_type()); | |
| 292 specifics.set_signin_scoped_device_id(info->signin_scoped_device_id()); | |
| 293 | |
| 294 if (has_local_device_backup_time()) { | |
| 295 specifics.set_backup_timestamp(local_device_backup_time()); | |
| 296 } | |
| 297 | |
| 298 return CreateLocalData(entity); | |
| 299 } | |
| 300 | |
| 301 SyncData DeviceInfoSyncService::CreateLocalData( | |
| 302 const sync_pb::EntitySpecifics& entity) { | |
| 303 const sync_pb::DeviceInfoSpecifics& specifics = entity.device_info(); | |
| 304 | |
| 305 std::string local_device_tag = | |
| 306 base::StringPrintf("DeviceInfo_%s", specifics.cache_guid().c_str()); | |
| 307 | |
| 308 return SyncData::CreateLocalData( | |
| 309 local_device_tag, specifics.client_name(), entity); | |
| 310 } | |
| 311 | |
| 312 DeviceInfo* DeviceInfoSyncService::CreateDeviceInfo( | |
| 313 const syncer::SyncData sync_data) { | |
| 314 const sync_pb::DeviceInfoSpecifics& specifics = | |
| 315 sync_data.GetSpecifics().device_info(); | |
| 316 | |
| 317 return new DeviceInfo(specifics.cache_guid(), | |
| 318 specifics.client_name(), | |
| 319 specifics.chrome_version(), | |
| 320 specifics.sync_user_agent(), | |
| 321 specifics.device_type(), | |
| 322 specifics.signin_scoped_device_id()); | |
| 323 } | |
| 324 | |
| 325 void DeviceInfoSyncService::StoreSyncData(const std::string& client_id, | |
| 326 const SyncData& sync_data) { | |
| 327 DVLOG(1) << "Storing DEVICE_INFO for " | |
| 328 << sync_data.GetSpecifics().device_info().client_name() | |
| 329 << " with ID " << client_id; | |
| 330 all_data_[client_id] = sync_data; | |
| 331 } | |
| 332 | |
| 333 void DeviceInfoSyncService::DeleteSyncData(const std::string& client_id) { | |
| 334 SyncDataMap::iterator iter = all_data_.find(client_id); | |
| 335 if (iter != all_data_.end()) { | |
| 336 DVLOG(1) << "Deleting DEVICE_INFO for " | |
| 337 << iter->second.GetSpecifics().device_info().client_name() | |
| 338 << " with ID " << client_id; | |
| 339 all_data_.erase(iter); | |
| 340 } | |
| 341 } | |
| 342 | |
| 343 } // namespace browser_sync | |
| OLD | NEW |