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 |