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 "components/sync_driver/device_info_sync_service.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <algorithm> | |
10 #include <utility> | |
11 | |
12 #include "base/memory/ptr_util.h" | |
13 #include "base/time/time.h" | |
14 #include "components/sync/api/sync_change.h" | |
15 #include "components/sync/base/time.h" | |
16 #include "components/sync/protocol/sync.pb.h" | |
17 #include "components/sync_driver/device_info_util.h" | |
18 #include "components/sync_driver/local_device_info_provider.h" | |
19 | |
20 namespace sync_driver { | |
21 | |
22 using base::Time; | |
23 using base::TimeDelta; | |
24 using syncer::ModelType; | |
25 using syncer::SyncChange; | |
26 using syncer::SyncChangeList; | |
27 using syncer::SyncChangeProcessor; | |
28 using syncer::SyncData; | |
29 using syncer::SyncDataList; | |
30 using syncer::SyncErrorFactory; | |
31 using syncer::SyncMergeResult; | |
32 | |
33 DeviceInfoSyncService::DeviceInfoSyncService( | |
34 LocalDeviceInfoProvider* local_device_info_provider) | |
35 : local_device_info_provider_(local_device_info_provider) { | |
36 DCHECK(local_device_info_provider); | |
37 } | |
38 | |
39 DeviceInfoSyncService::~DeviceInfoSyncService() { | |
40 } | |
41 | |
42 SyncMergeResult DeviceInfoSyncService::MergeDataAndStartSyncing( | |
43 ModelType type, | |
44 const SyncDataList& initial_sync_data, | |
45 std::unique_ptr<SyncChangeProcessor> sync_processor, | |
46 std::unique_ptr<SyncErrorFactory> error_handler) { | |
47 DCHECK(sync_processor.get()); | |
48 DCHECK(error_handler.get()); | |
49 DCHECK_EQ(type, syncer::DEVICE_INFO); | |
50 | |
51 DCHECK(!IsSyncing()); | |
52 | |
53 sync_processor_ = std::move(sync_processor); | |
54 error_handler_ = std::move(error_handler); | |
55 | |
56 // Initialization should be completed before this type is enabled | |
57 // and local device info must be available. | |
58 const DeviceInfo* local_device_info = | |
59 local_device_info_provider_->GetLocalDeviceInfo(); | |
60 DCHECK(local_device_info != NULL); | |
61 | |
62 // Indicates whether a local device has been added or updated. | |
63 // |change_type| defaults to ADD and might be changed to | |
64 // UPDATE to INVALID down below if the initial data contains | |
65 // data matching the local device ID. | |
66 SyncChange::SyncChangeType change_type = SyncChange::ACTION_ADD; | |
67 TimeDelta pulse_delay; | |
68 size_t num_items_new = 0; | |
69 size_t num_items_updated = 0; | |
70 | |
71 // Iterate over all initial sync data and copy it to the cache. | |
72 for (SyncDataList::const_iterator iter = initial_sync_data.begin(); | |
73 iter != initial_sync_data.end(); | |
74 ++iter) { | |
75 DCHECK_EQ(syncer::DEVICE_INFO, iter->GetDataType()); | |
76 | |
77 const std::string& id = iter->GetSpecifics().device_info().cache_guid(); | |
78 | |
79 if (id == local_device_info->guid()) { | |
80 // |initial_sync_data| contains data matching the local device. | |
81 std::unique_ptr<DeviceInfo> synced_local_device_info = | |
82 base::WrapUnique(CreateDeviceInfo(*iter)); | |
83 | |
84 pulse_delay = DeviceInfoUtil::CalculatePulseDelay( | |
85 GetLastUpdateTime(*iter), Time::Now()); | |
86 // Store the synced device info for the local device only if | |
87 // it is the same as the local info. Otherwise store the local | |
88 // device info and issue a change further below after finishing | |
89 // processing the |initial_sync_data|. | |
90 if (synced_local_device_info->Equals(*local_device_info) && | |
91 !pulse_delay.is_zero()) { | |
92 change_type = SyncChange::ACTION_INVALID; | |
93 } else { | |
94 num_items_updated++; | |
95 change_type = SyncChange::ACTION_UPDATE; | |
96 continue; | |
97 } | |
98 } else { | |
99 // A new device that doesn't match the local device. | |
100 num_items_new++; | |
101 } | |
102 | |
103 StoreSyncData(id, *iter); | |
104 } | |
105 | |
106 syncer::SyncMergeResult result(type); | |
107 | |
108 // If the SyncData for the local device is new or different then send it | |
109 // immediately, otherwise wait until the pulse interval has elapsed from the | |
110 // previous update. Regardless of the branch here we setup a timer loop with | |
111 // SendLocalData such that we continue pulsing every interval. | |
112 if (change_type == SyncChange::ACTION_INVALID) { | |
113 pulse_timer_.Start( | |
114 FROM_HERE, pulse_delay, | |
115 base::Bind(&DeviceInfoSyncService::SendLocalData, | |
116 base::Unretained(this), SyncChange::ACTION_UPDATE)); | |
117 } else { | |
118 SendLocalData(change_type); | |
119 } | |
120 | |
121 result.set_num_items_before_association(1); | |
122 result.set_num_items_after_association(all_data_.size()); | |
123 result.set_num_items_added(num_items_new); | |
124 result.set_num_items_modified(num_items_updated); | |
125 result.set_num_items_deleted(0); | |
126 | |
127 NotifyObservers(); | |
128 | |
129 return result; | |
130 } | |
131 | |
132 bool DeviceInfoSyncService::IsSyncing() const { | |
133 return !all_data_.empty(); | |
134 } | |
135 | |
136 void DeviceInfoSyncService::StopSyncing(syncer::ModelType type) { | |
137 bool was_syncing = IsSyncing(); | |
138 | |
139 pulse_timer_.Stop(); | |
140 all_data_.clear(); | |
141 sync_processor_.reset(); | |
142 error_handler_.reset(); | |
143 | |
144 if (was_syncing) { | |
145 NotifyObservers(); | |
146 } | |
147 } | |
148 | |
149 SyncDataList DeviceInfoSyncService::GetAllSyncData( | |
150 syncer::ModelType type) const { | |
151 SyncDataList list; | |
152 | |
153 for (SyncDataMap::const_iterator iter = all_data_.begin(); | |
154 iter != all_data_.end(); | |
155 ++iter) { | |
156 list.push_back(iter->second); | |
157 } | |
158 | |
159 return list; | |
160 } | |
161 | |
162 syncer::SyncError DeviceInfoSyncService::ProcessSyncChanges( | |
163 const tracked_objects::Location& from_here, | |
164 const SyncChangeList& change_list) { | |
165 syncer::SyncError error; | |
166 | |
167 DCHECK(local_device_info_provider_->GetLocalDeviceInfo()); | |
168 const std::string& local_device_id = | |
169 local_device_info_provider_->GetLocalDeviceInfo()->guid(); | |
170 | |
171 bool has_changes = false; | |
172 | |
173 // Iterate over all chanages and merge entries. | |
174 for (SyncChangeList::const_iterator iter = change_list.begin(); | |
175 iter != change_list.end(); | |
176 ++iter) { | |
177 const SyncData& sync_data = iter->sync_data(); | |
178 DCHECK_EQ(syncer::DEVICE_INFO, sync_data.GetDataType()); | |
179 | |
180 const std::string& client_id = | |
181 sync_data.GetSpecifics().device_info().cache_guid(); | |
182 // Ignore device info matching the local device. | |
183 if (local_device_id == client_id) { | |
184 DVLOG(1) << "Ignoring sync changes for the local DEVICE_INFO"; | |
185 continue; | |
186 } | |
187 | |
188 if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) { | |
189 has_changes = true; | |
190 DeleteSyncData(client_id); | |
191 } else if (iter->change_type() == syncer::SyncChange::ACTION_UPDATE || | |
192 iter->change_type() == syncer::SyncChange::ACTION_ADD) { | |
193 has_changes = true; | |
194 StoreSyncData(client_id, sync_data); | |
195 } else { | |
196 error.Reset(FROM_HERE, "Invalid action received.", syncer::DEVICE_INFO); | |
197 } | |
198 } | |
199 | |
200 if (has_changes) { | |
201 NotifyObservers(); | |
202 } | |
203 | |
204 return error; | |
205 } | |
206 | |
207 std::unique_ptr<DeviceInfo> DeviceInfoSyncService::GetDeviceInfo( | |
208 const std::string& client_id) const { | |
209 SyncDataMap::const_iterator iter = all_data_.find(client_id); | |
210 if (iter == all_data_.end()) { | |
211 return std::unique_ptr<DeviceInfo>(); | |
212 } | |
213 | |
214 return base::WrapUnique(CreateDeviceInfo(iter->second)); | |
215 } | |
216 | |
217 ScopedVector<DeviceInfo> DeviceInfoSyncService::GetAllDeviceInfo() const { | |
218 ScopedVector<DeviceInfo> list; | |
219 | |
220 for (SyncDataMap::const_iterator iter = all_data_.begin(); | |
221 iter != all_data_.end(); | |
222 ++iter) { | |
223 list.push_back(CreateDeviceInfo(iter->second)); | |
224 } | |
225 | |
226 return list; | |
227 } | |
228 | |
229 void DeviceInfoSyncService::AddObserver(Observer* observer) { | |
230 observers_.AddObserver(observer); | |
231 } | |
232 | |
233 void DeviceInfoSyncService::RemoveObserver(Observer* observer) { | |
234 observers_.RemoveObserver(observer); | |
235 } | |
236 | |
237 int DeviceInfoSyncService::CountActiveDevices() const { | |
238 return CountActiveDevices(Time::Now()); | |
239 } | |
240 | |
241 void DeviceInfoSyncService::NotifyObservers() { | |
242 FOR_EACH_OBSERVER(Observer, observers_, OnDeviceInfoChange()); | |
243 } | |
244 | |
245 SyncData DeviceInfoSyncService::CreateLocalData(const DeviceInfo* info) { | |
246 sync_pb::EntitySpecifics entity; | |
247 sync_pb::DeviceInfoSpecifics& specifics = *entity.mutable_device_info(); | |
248 | |
249 specifics.set_cache_guid(info->guid()); | |
250 specifics.set_client_name(info->client_name()); | |
251 specifics.set_chrome_version(info->chrome_version()); | |
252 specifics.set_sync_user_agent(info->sync_user_agent()); | |
253 specifics.set_device_type(info->device_type()); | |
254 specifics.set_signin_scoped_device_id(info->signin_scoped_device_id()); | |
255 specifics.set_last_updated_timestamp(syncer::TimeToProtoTime(Time::Now())); | |
256 | |
257 return CreateLocalData(entity); | |
258 } | |
259 | |
260 SyncData DeviceInfoSyncService::CreateLocalData( | |
261 const sync_pb::EntitySpecifics& entity) { | |
262 const sync_pb::DeviceInfoSpecifics& specifics = entity.device_info(); | |
263 return SyncData::CreateLocalData(DeviceInfoUtil::SpecificsToTag(specifics), | |
264 specifics.client_name(), entity); | |
265 } | |
266 | |
267 DeviceInfo* DeviceInfoSyncService::CreateDeviceInfo( | |
268 const syncer::SyncData& sync_data) { | |
269 const sync_pb::DeviceInfoSpecifics& specifics = | |
270 sync_data.GetSpecifics().device_info(); | |
271 | |
272 return new DeviceInfo(specifics.cache_guid(), | |
273 specifics.client_name(), | |
274 specifics.chrome_version(), | |
275 specifics.sync_user_agent(), | |
276 specifics.device_type(), | |
277 specifics.signin_scoped_device_id()); | |
278 } | |
279 | |
280 void DeviceInfoSyncService::StoreSyncData(const std::string& client_id, | |
281 const SyncData& sync_data) { | |
282 DVLOG(1) << "Storing DEVICE_INFO for " | |
283 << sync_data.GetSpecifics().device_info().client_name() | |
284 << " with ID " << client_id; | |
285 all_data_[client_id] = sync_data; | |
286 } | |
287 | |
288 void DeviceInfoSyncService::DeleteSyncData(const std::string& client_id) { | |
289 SyncDataMap::iterator iter = all_data_.find(client_id); | |
290 if (iter != all_data_.end()) { | |
291 DVLOG(1) << "Deleting DEVICE_INFO for " | |
292 << iter->second.GetSpecifics().device_info().client_name() | |
293 << " with ID " << client_id; | |
294 all_data_.erase(iter); | |
295 } | |
296 } | |
297 | |
298 void DeviceInfoSyncService::SendLocalData( | |
299 const SyncChange::SyncChangeType change_type) { | |
300 DCHECK_NE(change_type, SyncChange::ACTION_INVALID); | |
301 DCHECK(sync_processor_); | |
302 | |
303 const DeviceInfo* device_info = | |
304 local_device_info_provider_->GetLocalDeviceInfo(); | |
305 const SyncData& data = CreateLocalData(device_info); | |
306 StoreSyncData(device_info->guid(), data); | |
307 | |
308 SyncChangeList change_list; | |
309 change_list.push_back(SyncChange(FROM_HERE, change_type, data)); | |
310 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list); | |
311 | |
312 pulse_timer_.Start( | |
313 FROM_HERE, DeviceInfoUtil::kPulseInterval, | |
314 base::Bind(&DeviceInfoSyncService::SendLocalData, base::Unretained(this), | |
315 SyncChange::ACTION_UPDATE)); | |
316 } | |
317 | |
318 int DeviceInfoSyncService::CountActiveDevices(const Time now) const { | |
319 return std::count_if(all_data_.begin(), all_data_.end(), | |
320 [now](SyncDataMap::const_reference pair) { | |
321 return DeviceInfoUtil::IsActive( | |
322 GetLastUpdateTime(pair.second), now); | |
323 }); | |
324 } | |
325 | |
326 // static | |
327 Time DeviceInfoSyncService::GetLastUpdateTime(const SyncData& device_info) { | |
328 if (device_info.GetSpecifics().device_info().has_last_updated_timestamp()) { | |
329 return syncer::ProtoTimeToTime( | |
330 device_info.GetSpecifics().device_info().last_updated_timestamp()); | |
331 } else if (!device_info.IsLocal()) { | |
332 // If there is no |last_updated_timestamp| present, fallback to mod time. | |
333 return syncer::SyncDataRemote(device_info).GetModifiedTime(); | |
334 } else { | |
335 // We shouldn't reach this point for remote data, so this means we're likely | |
336 // looking at the local device info. Using a long ago time is perfect, since | |
337 // the desired behavior is to update/pulse our data as soon as possible. | |
338 return Time(); | |
339 } | |
340 } | |
341 | |
342 } // namespace sync_driver | |
OLD | NEW |