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