OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/sync_sessions/sessions_sync_manager.h" | 5 #include "components/sync_sessions/sessions_sync_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/format_macros.h" | |
11 #include "base/logging.h" | |
10 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
11 #include "base/metrics/field_trial.h" | 13 #include "base/metrics/field_trial.h" |
12 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
15 #include "base/strings/stringprintf.h" | |
13 #include "build/build_config.h" | 16 #include "build/build_config.h" |
14 #include "components/sync/base/hash_util.h" | 17 #include "components/sync/base/hash_util.h" |
15 #include "components/sync/device_info/local_device_info_provider.h" | 18 #include "components/sync/device_info/local_device_info_provider.h" |
16 #include "components/sync/model/sync_error.h" | 19 #include "components/sync/model/sync_error.h" |
17 #include "components/sync/model/sync_error_factory.h" | 20 #include "components/sync/model/sync_error_factory.h" |
18 #include "components/sync/model/sync_merge_result.h" | 21 #include "components/sync/model/sync_merge_result.h" |
19 #include "components/sync/model/time.h" | 22 #include "components/sync/model/time.h" |
20 #include "components/sync_sessions/sync_sessions_client.h" | 23 #include "components/sync_sessions/sync_sessions_client.h" |
21 #include "components/sync_sessions/synced_tab_delegate.h" | 24 #include "components/sync_sessions/synced_tab_delegate.h" |
22 #include "components/sync_sessions/synced_window_delegate.h" | 25 #include "components/sync_sessions/synced_window_delegate.h" |
23 #include "components/sync_sessions/synced_window_delegates_getter.h" | 26 #include "components/sync_sessions/synced_window_delegates_getter.h" |
27 #include "components/sync_sessions/tab_node_pool.h" | |
24 #include "components/variations/variations_associated_data.h" | 28 #include "components/variations/variations_associated_data.h" |
25 | 29 |
26 using sessions::SerializedNavigationEntry; | 30 using sessions::SerializedNavigationEntry; |
27 using syncer::DeviceInfo; | 31 using syncer::DeviceInfo; |
28 using syncer::LocalDeviceInfoProvider; | 32 using syncer::LocalDeviceInfoProvider; |
29 using syncer::SyncChange; | 33 using syncer::SyncChange; |
30 using syncer::SyncData; | 34 using syncer::SyncData; |
31 | 35 |
32 namespace sync_sessions { | 36 namespace sync_sessions { |
33 | 37 |
(...skipping 21 matching lines...) Expand all Loading... | |
55 return t1->timestamp > t2->timestamp; | 59 return t1->timestamp > t2->timestamp; |
56 } | 60 } |
57 | 61 |
58 // Comparator function for use with std::sort that will sort sessions by | 62 // Comparator function for use with std::sort that will sort sessions by |
59 // descending modified_time (i.e., most recent first). | 63 // descending modified_time (i.e., most recent first). |
60 bool SessionsRecencyComparator(const SyncedSession* s1, | 64 bool SessionsRecencyComparator(const SyncedSession* s1, |
61 const SyncedSession* s2) { | 65 const SyncedSession* s2) { |
62 return s1->modified_time > s2->modified_time; | 66 return s1->modified_time > s2->modified_time; |
63 } | 67 } |
64 | 68 |
69 std::string TabNodeIdToTag(const std::string& machine_tag, int tab_node_id) { | |
70 CHECK_GT(tab_node_id, TabNodePool::kInvalidTabNodeID) << "crbug.com/673618"; | |
71 return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id); | |
72 } | |
73 | |
65 std::string TagFromSpecifics(const sync_pb::SessionSpecifics& specifics) { | 74 std::string TagFromSpecifics(const sync_pb::SessionSpecifics& specifics) { |
66 if (specifics.has_header()) { | 75 if (specifics.has_header()) { |
67 return specifics.session_tag(); | 76 return specifics.session_tag(); |
68 } else if (specifics.has_tab()) { | 77 } else if (specifics.has_tab()) { |
69 return TabNodePool::TabIdToTag(specifics.session_tag(), | 78 return TabNodeIdToTag(specifics.session_tag(), specifics.tab_node_id()); |
70 specifics.tab_node_id()); | |
71 } else { | 79 } else { |
72 return std::string(); | 80 return std::string(); |
73 } | 81 } |
74 } | 82 } |
75 | 83 |
84 sync_pb::SessionSpecifics SessionTabToSpecifics( | |
85 const sessions::SessionTab& session_tab, | |
86 const std::string& local_tag, | |
87 int tab_node_id) { | |
88 sync_pb::SessionSpecifics specifics; | |
89 specifics.mutable_tab()->CopyFrom(session_tab.ToSyncData()); | |
90 specifics.set_session_tag(local_tag); | |
91 specifics.set_tab_node_id(tab_node_id); | |
92 return specifics; | |
93 } | |
94 | |
76 } // namespace | 95 } // namespace |
77 | 96 |
78 // |local_device| is owned by ProfileSyncService, its lifetime exceeds | 97 // |local_device| is owned by ProfileSyncService, its lifetime exceeds |
79 // lifetime of SessionSyncManager. | 98 // lifetime of SessionSyncManager. |
80 SessionsSyncManager::SessionsSyncManager( | 99 SessionsSyncManager::SessionsSyncManager( |
81 sync_sessions::SyncSessionsClient* sessions_client, | 100 sync_sessions::SyncSessionsClient* sessions_client, |
82 syncer::SyncPrefs* sync_prefs, | 101 syncer::SyncPrefs* sync_prefs, |
83 LocalDeviceInfoProvider* local_device, | 102 LocalDeviceInfoProvider* local_device, |
84 std::unique_ptr<LocalSessionEventRouter> router, | 103 std::unique_ptr<LocalSessionEventRouter> router, |
85 const base::Closure& sessions_updated_callback, | 104 const base::Closure& sessions_updated_callback, |
(...skipping 24 matching lines...) Expand all Loading... | |
110 return machine_tag; | 129 return machine_tag; |
111 } | 130 } |
112 | 131 |
113 syncer::SyncMergeResult SessionsSyncManager::MergeDataAndStartSyncing( | 132 syncer::SyncMergeResult SessionsSyncManager::MergeDataAndStartSyncing( |
114 syncer::ModelType type, | 133 syncer::ModelType type, |
115 const syncer::SyncDataList& initial_sync_data, | 134 const syncer::SyncDataList& initial_sync_data, |
116 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, | 135 std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, |
117 std::unique_ptr<syncer::SyncErrorFactory> error_handler) { | 136 std::unique_ptr<syncer::SyncErrorFactory> error_handler) { |
118 syncer::SyncMergeResult merge_result(type); | 137 syncer::SyncMergeResult merge_result(type); |
119 DCHECK(session_tracker_.Empty()); | 138 DCHECK(session_tracker_.Empty()); |
120 DCHECK_EQ(0U, local_tab_pool_.Capacity()); | |
121 | 139 |
122 error_handler_ = std::move(error_handler); | 140 error_handler_ = std::move(error_handler); |
123 sync_processor_ = std::move(sync_processor); | 141 sync_processor_ = std::move(sync_processor); |
124 | 142 |
125 // SessionDataTypeController ensures that the local device info | 143 // SessionDataTypeController ensures that the local device info |
126 // is available before activating this datatype. | 144 // is available before activating this datatype. |
127 DCHECK(local_device_); | 145 DCHECK(local_device_); |
128 const DeviceInfo* local_device_info = local_device_->GetLocalDeviceInfo(); | 146 const DeviceInfo* local_device_info = local_device_->GetLocalDeviceInfo(); |
129 if (!local_device_info) { | 147 if (!local_device_info) { |
130 merge_result.set_error(error_handler_->CreateAndUploadError( | 148 merge_result.set_error(error_handler_->CreateAndUploadError( |
(...skipping 15 matching lines...) Expand all Loading... | |
146 | 164 |
147 local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID; | 165 local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID; |
148 | 166 |
149 // Make sure we have a machine tag. We do this now (versus earlier) as it's | 167 // Make sure we have a machine tag. We do this now (versus earlier) as it's |
150 // a conveniently safe time to assert sync is ready and the cache_guid is | 168 // a conveniently safe time to assert sync is ready and the cache_guid is |
151 // initialized. | 169 // initialized. |
152 if (current_machine_tag_.empty()) { | 170 if (current_machine_tag_.empty()) { |
153 InitializeCurrentMachineTag(local_device_->GetLocalSyncCacheGUID()); | 171 InitializeCurrentMachineTag(local_device_->GetLocalSyncCacheGUID()); |
154 } | 172 } |
155 | 173 |
156 session_tracker_.SetLocalSessionTag(current_machine_tag_); | 174 session_tracker_.SetLocalSessionTag(current_machine_tag()); |
157 | 175 |
158 syncer::SyncChangeList new_changes; | 176 syncer::SyncChangeList new_changes; |
159 | 177 |
160 // First, we iterate over sync data to update our session_tracker_. | 178 // First, we iterate over sync data to update our session_tracker_. |
161 syncer::SyncDataList restored_tabs; | 179 if (!InitFromSyncModel(initial_sync_data, &new_changes)) { |
162 if (!InitFromSyncModel(initial_sync_data, &restored_tabs, &new_changes)) { | |
163 // The sync db didn't have a header node for us. Create one. | 180 // The sync db didn't have a header node for us. Create one. |
164 sync_pb::EntitySpecifics specifics; | 181 sync_pb::EntitySpecifics specifics; |
165 sync_pb::SessionSpecifics* base_specifics = specifics.mutable_session(); | 182 sync_pb::SessionSpecifics* base_specifics = specifics.mutable_session(); |
166 base_specifics->set_session_tag(current_machine_tag()); | 183 base_specifics->set_session_tag(current_machine_tag()); |
167 sync_pb::SessionHeader* header_s = base_specifics->mutable_header(); | 184 sync_pb::SessionHeader* header_s = base_specifics->mutable_header(); |
168 header_s->set_client_name(current_session_name_); | 185 header_s->set_client_name(current_session_name_); |
169 header_s->set_device_type(current_device_type_); | 186 header_s->set_device_type(current_device_type_); |
170 syncer::SyncData data = syncer::SyncData::CreateLocalData( | 187 syncer::SyncData data = syncer::SyncData::CreateLocalData( |
171 current_machine_tag(), current_session_name_, specifics); | 188 current_machine_tag(), current_session_name_, specifics); |
172 new_changes.push_back( | 189 new_changes.push_back( |
173 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD, data)); | 190 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD, data)); |
174 } | 191 } |
175 | 192 |
176 #if defined(OS_ANDROID) | 193 #if defined(OS_ANDROID) |
177 std::string sync_machine_tag( | 194 std::string sync_machine_tag( |
178 BuildMachineTag(local_device_->GetLocalSyncCacheGUID())); | 195 BuildMachineTag(local_device_->GetLocalSyncCacheGUID())); |
179 if (current_machine_tag_.compare(sync_machine_tag) != 0) | 196 if (current_machine_tag().compare(sync_machine_tag) != 0) |
180 DeleteForeignSessionInternal(sync_machine_tag, &new_changes); | 197 DeleteForeignSessionInternal(sync_machine_tag, &new_changes); |
181 #endif | 198 #endif |
182 | 199 |
183 // Check if anything has changed on the local client side. | 200 // Check if anything has changed on the local client side. |
184 AssociateWindows(RELOAD_TABS, restored_tabs, &new_changes); | 201 AssociateWindows(RELOAD_TABS, &new_changes); |
185 local_tab_pool_out_of_sync_ = false; | 202 local_tab_pool_out_of_sync_ = false; |
186 | 203 |
187 merge_result.set_error( | 204 merge_result.set_error( |
188 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); | 205 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); |
189 | 206 |
190 local_event_router_->StartRoutingTo(this); | 207 local_event_router_->StartRoutingTo(this); |
191 return merge_result; | 208 return merge_result; |
192 } | 209 } |
193 | 210 |
194 void SessionsSyncManager::AssociateWindows( | 211 void SessionsSyncManager::AssociateWindows( |
195 ReloadTabsOption option, | 212 ReloadTabsOption option, |
196 const syncer::SyncDataList& restored_tabs, | |
197 syncer::SyncChangeList* change_output) { | 213 syncer::SyncChangeList* change_output) { |
198 const std::string local_tag = current_machine_tag(); | 214 const std::string local_tag = current_machine_tag(); |
199 sync_pb::SessionSpecifics specifics; | 215 sync_pb::SessionSpecifics specifics; |
200 specifics.set_session_tag(local_tag); | 216 specifics.set_session_tag(local_tag); |
201 sync_pb::SessionHeader* header_s = specifics.mutable_header(); | 217 sync_pb::SessionHeader* header_s = specifics.mutable_header(); |
202 SyncedSession* current_session = session_tracker_.GetSession(local_tag); | 218 SyncedSession* current_session = session_tracker_.GetSession(local_tag); |
203 current_session->modified_time = base::Time::Now(); | 219 current_session->modified_time = base::Time::Now(); |
204 header_s->set_client_name(current_session_name_); | 220 header_s->set_client_name(current_session_name_); |
205 header_s->set_device_type(current_device_type_); | 221 header_s->set_device_type(current_device_type_); |
206 | 222 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
255 | 271 |
256 bool found_tabs = false; | 272 bool found_tabs = false; |
257 for (int j = 0; j < (*i)->GetTabCount(); ++j) { | 273 for (int j = 0; j < (*i)->GetTabCount(); ++j) { |
258 SessionID::id_type tab_id = (*i)->GetTabIdAt(j); | 274 SessionID::id_type tab_id = (*i)->GetTabIdAt(j); |
259 SyncedTabDelegate* synced_tab = (*i)->GetTabAt(j); | 275 SyncedTabDelegate* synced_tab = (*i)->GetTabAt(j); |
260 | 276 |
261 // GetTabAt can return a null tab; in that case just skip it. | 277 // GetTabAt can return a null tab; in that case just skip it. |
262 if (!synced_tab) | 278 if (!synced_tab) |
263 continue; | 279 continue; |
264 | 280 |
281 // Placeholder tabs are those without WebContents, either because they | |
282 // were never loaded into memory or they were evicted from memory | |
283 // (typically only on Android devices). They only have a tab id, window | |
284 // id, and a saved synced id (corresponding to the tab node id). Note | |
285 // that only placeholders have this sync id, as it's necessary to | |
286 // properly reassociate the tab with the entity that was backing it. | |
265 if (synced_tab->IsPlaceholderTab()) { | 287 if (synced_tab->IsPlaceholderTab()) { |
266 // For tabs without WebContents update the |tab_id| and |window_id|, | 288 // For tabs without WebContents update the |tab_id| and |window_id|, |
267 // as it could have changed after a session restore. | 289 // as it could have changed after a session restore. |
268 // Note: We cannot check if a tab is valid if it has no WebContents. | |
269 // We assume any such tab is valid and leave the contents of | |
270 // corresponding sync node unchanged. | |
271 if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID && | 290 if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID && |
Patrick Noland
2017/01/25 19:23:41
Not part of the current change, but this would be
Nicolas Zea
2017/01/25 23:55:04
This is just checking that the tab and tab node id
| |
272 tab_id > TabNodePool::kInvalidTabID) { | 291 tab_id > TabNodePool::kInvalidTabID) { |
273 AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id, | 292 AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id, |
274 restored_tabs, change_output); | 293 change_output); |
275 found_tabs = true; | |
276 window_s.add_tab(tab_id); | |
277 } | 294 } |
278 continue; | 295 } else if (RELOAD_TABS == option) { |
296 AssociateTab(synced_tab, change_output); | |
279 } | 297 } |
280 | 298 |
281 if (RELOAD_TABS == option) | |
282 AssociateTab(synced_tab, change_output); | |
283 | |
284 // If the tab is valid, it would have been added to the tracker either | 299 // If the tab is valid, it would have been added to the tracker either |
285 // by the above AssociateTab call (at association time), or by the | 300 // by the above AssociateTab call (at association time), or by the |
286 // change processor calling AssociateTab for all modified tabs. | 301 // change processor calling AssociateTab for all modified tabs. |
287 // Therefore, we can key whether this window has valid tabs based on | 302 // Therefore, we can key whether this window has valid tabs based on |
288 // the tab's presence in the tracker. | 303 // the tab's presence in the tracker. |
289 const sessions::SessionTab* tab = nullptr; | 304 const sessions::SessionTab* tab = nullptr; |
290 if (session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) { | 305 if (session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) { |
291 found_tabs = true; | 306 found_tabs = true; |
292 window_s.add_tab(tab_id); | 307 window_s.add_tab(tab_id); |
293 } | 308 } |
294 } | 309 } |
295 if (found_tabs) { | 310 if (found_tabs) { |
296 sync_pb::SessionWindow* header_window = header_s->add_window(); | 311 sync_pb::SessionWindow* header_window = header_s->add_window(); |
297 *header_window = window_s; | 312 *header_window = window_s; |
298 | 313 |
299 // Update this window's representation in the synced session tracker. | 314 // Update this window's representation in the synced session tracker. |
300 session_tracker_.PutWindowInSession(local_tag, window_id); | 315 session_tracker_.PutWindowInSession(local_tag, window_id); |
301 BuildSyncedSessionFromSpecifics( | 316 BuildSyncedSessionFromSpecifics( |
302 local_tag, window_s, current_session->modified_time, | 317 local_tag, window_s, current_session->modified_time, |
303 current_session->windows[window_id].get()); | 318 current_session->windows[window_id].get()); |
304 } | 319 } |
305 } | 320 } |
306 } | 321 } |
307 local_tab_pool_.DeleteUnassociatedTabNodes(change_output); | 322 std::set<int> deleted_tab_node_ids; |
308 session_tracker_.CleanupSession(local_tag); | 323 session_tracker_.CleanupLocalTabs(&deleted_tab_node_ids); |
324 for (int tab_node_id : deleted_tab_node_ids) { | |
Patrick Noland
2017/01/25 19:23:41
Might be worth making a helper to delete a list of
Nicolas Zea
2017/01/25 23:55:04
Done.
| |
325 std::string tab_node_tag = | |
326 TabNodeIdToTag(current_machine_tag(), tab_node_id); | |
327 change_output->push_back(syncer::SyncChange( | |
328 FROM_HERE, syncer::SyncChange::ACTION_DELETE, | |
329 syncer::SyncData::CreateLocalDelete(tab_node_tag, syncer::SESSIONS))); | |
330 } | |
309 | 331 |
310 // Always update the header. Sync takes care of dropping this update | 332 // Always update the header. Sync takes care of dropping this update |
311 // if the entity specifics are identical (i.e windows, client name did | 333 // if the entity specifics are identical (i.e windows, client name did |
312 // not change). | 334 // not change). |
313 sync_pb::EntitySpecifics entity; | 335 sync_pb::EntitySpecifics entity; |
314 entity.mutable_session()->CopyFrom(specifics); | 336 entity.mutable_session()->CopyFrom(specifics); |
315 syncer::SyncData data = syncer::SyncData::CreateLocalData( | 337 syncer::SyncData data = syncer::SyncData::CreateLocalData( |
316 current_machine_tag(), current_session_name_, entity); | 338 current_machine_tag(), current_session_name_, entity); |
317 change_output->push_back( | 339 change_output->push_back( |
318 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); | 340 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); |
319 } | 341 } |
320 | 342 |
321 void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab, | 343 void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab_delegate, |
322 syncer::SyncChangeList* change_output) { | 344 syncer::SyncChangeList* change_output) { |
323 DCHECK(!tab->IsPlaceholderTab()); | 345 DCHECK(!tab_delegate->IsPlaceholderTab()); |
324 SessionID::id_type tab_id = tab->GetSessionId(); | |
325 | 346 |
326 if (tab->IsBeingDestroyed()) { | 347 if (tab_delegate->IsBeingDestroyed()) { |
327 // This tab is closing. | 348 // Do nothing. By not proactively adding the tab to the session, it will be |
328 TabLinksMap::iterator tab_iter = local_tab_map_.find(tab_id); | 349 // removed if necessary during subsequent cleanup. |
329 if (tab_iter == local_tab_map_.end()) { | |
330 // We aren't tracking this tab (for example, sync setting page). | |
331 return; | |
332 } | |
333 local_tab_pool_.FreeTabNode(tab_iter->second->tab_node_id(), change_output); | |
334 local_tab_map_.erase(tab_iter); | |
335 return; | 350 return; |
336 } | 351 } |
337 | 352 |
338 if (!tab->ShouldSync(sessions_client_)) | 353 if (!tab_delegate->ShouldSync(sessions_client_)) |
339 return; | 354 return; |
340 | 355 |
341 TabLinksMap::iterator local_tab_map_iter = local_tab_map_.find(tab_id); | 356 SessionID::id_type tab_id = tab_delegate->GetSessionId(); |
342 TabLink* tab_link = nullptr; | 357 DVLOG(1) << "Syncing tab " << tab_id << " from window " |
358 << tab_delegate->GetWindowId(); | |
343 | 359 |
344 if (local_tab_map_iter == local_tab_map_.end()) { | 360 int tab_node_id = TabNodePool::kInvalidTabNodeID; |
345 int tab_node_id = tab->GetSyncId(); | 361 bool existing_tab_node = |
346 // If there is an old sync node for the tab, reuse it. If this is a new | 362 session_tracker_.GetTabNodeForLocalTab(tab_id, &tab_node_id); |
347 // tab, get a sync node for it. | 363 CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id) << "crbug.com/673618"; |
348 if (!local_tab_pool_.IsUnassociatedTabNode(tab_node_id)) { | 364 tab_delegate->SetSyncId(tab_node_id); |
349 tab_node_id = local_tab_pool_.GetFreeTabNode(change_output); | 365 sessions::SessionTab* session_tab = |
350 tab->SetSyncId(tab_node_id); | 366 session_tracker_.GetTab(current_machine_tag(), tab_id); |
351 } | |
352 local_tab_pool_.AssociateTabNode(tab_node_id, tab_id); | |
353 tab_link = new TabLink(tab_node_id, tab); | |
354 local_tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link); | |
355 } else { | |
356 // This tab is already associated with a sync node, reuse it. | |
357 // Note: on some platforms the tab object may have changed, so we ensure | |
358 // the tab link is up to date. | |
359 tab_link = local_tab_map_iter->second.get(); | |
360 local_tab_map_iter->second->set_tab(tab); | |
361 } | |
362 DCHECK(tab_link); | |
363 DCHECK_NE(tab_link->tab_node_id(), TabNodePool::kInvalidTabNodeID); | |
364 DVLOG(1) << "Reloading tab " << tab_id << " from window " | |
365 << tab->GetWindowId(); | |
366 | 367 |
367 // Write to sync model. | 368 // Get the previously synced url. |
368 sync_pb::EntitySpecifics specifics; | 369 int old_index = session_tab->normalized_navigation_index(); |
369 LocalTabDelegateToSpecifics(*tab, specifics.mutable_session()); | 370 GURL old_url; |
370 syncer::SyncData data = syncer::SyncData::CreateLocalData( | 371 if (session_tab->navigations.size() > static_cast<size_t>(old_index)) |
371 TabNodePool::TabIdToTag(current_machine_tag_, tab_link->tab_node_id()), | 372 old_url = session_tab->navigations[old_index].virtual_url(); |
372 current_session_name_, specifics); | |
373 change_output->push_back( | |
374 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); | |
375 | 373 |
376 int current_index = tab->GetCurrentEntryIndex(); | 374 // Update the tracker's session representation. |
377 const GURL new_url = tab->GetVirtualURLAtIndex(current_index); | 375 SetSessionTabFromDelegate(*tab_delegate, base::Time::Now(), session_tab); |
378 if (new_url != tab_link->url()) { | 376 SetVariationIds(session_tab); |
379 tab_link->set_url(new_url); | |
380 favicon_cache_.OnFaviconVisited(new_url, | |
381 tab->GetFaviconURLAtIndex(current_index)); | |
382 page_revisit_broadcaster_.OnPageVisit( | |
383 new_url, tab->GetTransitionAtIndex(current_index)); | |
384 } | |
385 | |
386 session_tracker_.GetSession(current_machine_tag())->modified_time = | 377 session_tracker_.GetSession(current_machine_tag())->modified_time = |
387 base::Time::Now(); | 378 base::Time::Now(); |
379 | |
380 // Write to the sync model itself. | |
381 sync_pb::EntitySpecifics specifics; | |
382 specifics.mutable_session()->CopyFrom( | |
383 SessionTabToSpecifics(*session_tab, current_machine_tag(), tab_node_id)); | |
384 syncer::SyncData data = syncer::SyncData::CreateLocalData( | |
385 TabNodeIdToTag(current_machine_tag(), tab_node_id), current_session_name_, | |
386 specifics); | |
387 change_output->push_back(syncer::SyncChange( | |
388 FROM_HERE, existing_tab_node ? syncer::SyncChange::ACTION_UPDATE | |
389 : syncer::SyncChange::ACTION_ADD, | |
390 data)); | |
391 | |
392 int current_index = tab_delegate->GetCurrentEntryIndex(); | |
393 const GURL new_url = tab_delegate->GetVirtualURLAtIndex(current_index); | |
394 if (new_url != old_url) { | |
395 favicon_cache_.OnFaviconVisited( | |
396 new_url, tab_delegate->GetFaviconURLAtIndex(current_index)); | |
397 page_revisit_broadcaster_.OnPageVisit( | |
398 new_url, tab_delegate->GetTransitionAtIndex(current_index)); | |
399 } | |
388 } | 400 } |
389 | 401 |
390 bool SessionsSyncManager::RebuildAssociations() { | 402 bool SessionsSyncManager::RebuildAssociations() { |
391 syncer::SyncDataList data(sync_processor_->GetAllSyncData(syncer::SESSIONS)); | 403 syncer::SyncDataList data(sync_processor_->GetAllSyncData(syncer::SESSIONS)); |
392 std::unique_ptr<syncer::SyncErrorFactory> error_handler( | 404 std::unique_ptr<syncer::SyncErrorFactory> error_handler( |
393 std::move(error_handler_)); | 405 std::move(error_handler_)); |
394 std::unique_ptr<syncer::SyncChangeProcessor> processor( | 406 std::unique_ptr<syncer::SyncChangeProcessor> processor( |
395 std::move(sync_processor_)); | 407 std::move(sync_processor_)); |
396 | 408 |
397 StopSyncing(syncer::SESSIONS); | 409 StopSyncing(syncer::SESSIONS); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
437 DCHECK(!rebuild_association_succeeded || !local_tab_pool_out_of_sync_); | 449 DCHECK(!rebuild_association_succeeded || !local_tab_pool_out_of_sync_); |
438 return; | 450 return; |
439 } | 451 } |
440 | 452 |
441 syncer::SyncChangeList changes; | 453 syncer::SyncChangeList changes; |
442 AssociateTab(modified_tab, &changes); | 454 AssociateTab(modified_tab, &changes); |
443 // Note, we always associate windows because it's possible a tab became | 455 // Note, we always associate windows because it's possible a tab became |
444 // "interesting" by going to a valid URL, in which case it needs to be added | 456 // "interesting" by going to a valid URL, in which case it needs to be added |
445 // to the window's tab information. Similarly, if a tab became | 457 // to the window's tab information. Similarly, if a tab became |
446 // "uninteresting", we remove it from the window's tab information. | 458 // "uninteresting", we remove it from the window's tab information. |
447 AssociateWindows(DONT_RELOAD_TABS, syncer::SyncDataList(), &changes); | 459 AssociateWindows(DONT_RELOAD_TABS, &changes); |
448 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); | 460 sync_processor_->ProcessSyncChanges(FROM_HERE, changes); |
449 } | 461 } |
450 | 462 |
451 void SessionsSyncManager::OnFaviconsChanged(const std::set<GURL>& page_urls, | 463 void SessionsSyncManager::OnFaviconsChanged(const std::set<GURL>& page_urls, |
452 const GURL& /* icon_url */) { | 464 const GURL& /* icon_url */) { |
453 // TODO(zea): consider a separate container for tabs with outstanding favicon | 465 for (const GURL& page_url : page_urls) |
454 // loads so we don't have to iterate through all tabs comparing urls. | 466 favicon_cache_.OnPageFaviconUpdated(page_url); |
455 for (const GURL& page_url : page_urls) { | |
456 for (TabLinksMap::iterator tab_iter = local_tab_map_.begin(); | |
457 tab_iter != local_tab_map_.end(); ++tab_iter) { | |
458 if (tab_iter->second->url() == page_url) | |
459 favicon_cache_.OnPageFaviconUpdated(page_url); | |
460 } | |
461 } | |
462 } | 467 } |
463 | 468 |
464 void SessionsSyncManager::StopSyncing(syncer::ModelType type) { | 469 void SessionsSyncManager::StopSyncing(syncer::ModelType type) { |
465 local_event_router_->Stop(); | 470 local_event_router_->Stop(); |
466 if (sync_processor_.get() && lost_navigations_recorder_.get()) { | 471 if (sync_processor_.get() && lost_navigations_recorder_.get()) { |
467 sync_processor_->RemoveLocalChangeObserver( | 472 sync_processor_->RemoveLocalChangeObserver( |
468 lost_navigations_recorder_.get()); | 473 lost_navigations_recorder_.get()); |
469 lost_navigations_recorder_.reset(); | 474 lost_navigations_recorder_.reset(); |
470 } | 475 } |
471 sync_processor_.reset(nullptr); | 476 sync_processor_.reset(nullptr); |
472 error_handler_.reset(); | 477 error_handler_.reset(); |
473 session_tracker_.Clear(); | 478 session_tracker_.Clear(); |
474 local_tab_map_.clear(); | |
475 local_tab_pool_.Clear(); | |
476 current_machine_tag_.clear(); | 479 current_machine_tag_.clear(); |
477 current_session_name_.clear(); | 480 current_session_name_.clear(); |
478 local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID; | 481 local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID; |
479 } | 482 } |
480 | 483 |
481 syncer::SyncDataList SessionsSyncManager::GetAllSyncData( | 484 syncer::SyncDataList SessionsSyncManager::GetAllSyncData( |
482 syncer::ModelType type) const { | 485 syncer::ModelType type) const { |
483 syncer::SyncDataList list; | 486 syncer::SyncDataList list; |
484 const SyncedSession* session = nullptr; | 487 const SyncedSession* session = nullptr; |
485 if (!session_tracker_.LookupLocalSession(&session)) | 488 if (!session_tracker_.LookupLocalSession(&session)) |
486 return syncer::SyncDataList(); | 489 return syncer::SyncDataList(); |
487 | 490 |
488 // First construct the header node. | 491 // First construct the header node. |
489 sync_pb::EntitySpecifics header_entity; | 492 sync_pb::EntitySpecifics header_entity; |
490 header_entity.mutable_session()->set_session_tag(current_machine_tag()); | 493 header_entity.mutable_session()->set_session_tag(current_machine_tag()); |
491 sync_pb::SessionHeader* header_specifics = | 494 sync_pb::SessionHeader* header_specifics = |
492 header_entity.mutable_session()->mutable_header(); | 495 header_entity.mutable_session()->mutable_header(); |
493 header_specifics->MergeFrom(session->ToSessionHeader()); | 496 header_specifics->MergeFrom(session->ToSessionHeader()); |
494 syncer::SyncData data = syncer::SyncData::CreateLocalData( | 497 syncer::SyncData data = syncer::SyncData::CreateLocalData( |
495 current_machine_tag(), current_session_name_, header_entity); | 498 current_machine_tag(), current_session_name_, header_entity); |
496 list.push_back(data); | 499 list.push_back(data); |
497 | 500 |
498 for (auto win_iter = session->windows.begin(); | 501 for (auto& win_iter : session->windows) { |
499 win_iter != session->windows.end(); ++win_iter) { | 502 for (auto& tab : win_iter.second->tabs) { |
500 for (auto tabs_iter = win_iter->second->tabs.begin(); | 503 // TODO(zea): replace with with the correct tab node id once there's a |
501 tabs_iter != win_iter->second->tabs.end(); ++tabs_iter) { | 504 // sync specific wrapper for SessionTab. This method is only used in |
505 // tests though, so it's fine for now. crbug.com/662597 | |
506 int tab_node_id = 0; | |
502 sync_pb::EntitySpecifics entity; | 507 sync_pb::EntitySpecifics entity; |
503 sync_pb::SessionSpecifics* specifics = entity.mutable_session(); | 508 entity.mutable_session()->CopyFrom( |
504 specifics->mutable_tab()->MergeFrom((*tabs_iter)->ToSyncData()); | 509 SessionTabToSpecifics(*tab, current_machine_tag(), tab_node_id)); |
505 specifics->set_session_tag(current_machine_tag_); | |
506 | |
507 TabLinksMap::const_iterator tab_map_iter = | |
508 local_tab_map_.find((*tabs_iter)->tab_id.id()); | |
509 DCHECK(tab_map_iter != local_tab_map_.end()); | |
510 specifics->set_tab_node_id(tab_map_iter->second->tab_node_id()); | |
511 syncer::SyncData data = syncer::SyncData::CreateLocalData( | 510 syncer::SyncData data = syncer::SyncData::CreateLocalData( |
512 TabNodePool::TabIdToTag(current_machine_tag_, | 511 TabNodeIdToTag(current_machine_tag(), tab_node_id), |
513 specifics->tab_node_id()), | |
514 current_session_name_, entity); | 512 current_session_name_, entity); |
515 list.push_back(data); | 513 list.push_back(data); |
516 } | 514 } |
517 } | 515 } |
518 return list; | 516 return list; |
519 } | 517 } |
520 | 518 |
521 bool SessionsSyncManager::GetLocalSession(const SyncedSession** local_session) { | 519 bool SessionsSyncManager::GetLocalSession(const SyncedSession** local_session) { |
522 if (current_machine_tag_.empty()) | 520 if (current_machine_tag().empty()) |
523 return false; | 521 return false; |
524 *local_session = session_tracker_.GetSession(current_machine_tag()); | 522 *local_session = session_tracker_.GetSession(current_machine_tag()); |
525 return true; | 523 return true; |
526 } | 524 } |
527 | 525 |
528 syncer::SyncError SessionsSyncManager::ProcessSyncChanges( | 526 syncer::SyncError SessionsSyncManager::ProcessSyncChanges( |
529 const tracked_objects::Location& from_here, | 527 const tracked_objects::Location& from_here, |
530 const syncer::SyncChangeList& change_list) { | 528 const syncer::SyncChangeList& change_list) { |
531 if (!sync_processor_.get()) { | 529 if (!sync_processor_.get()) { |
532 syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR, | 530 syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR, |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
572 break; | 570 break; |
573 case syncer::SyncChange::ACTION_ADD: | 571 case syncer::SyncChange::ACTION_ADD: |
574 case syncer::SyncChange::ACTION_UPDATE: | 572 case syncer::SyncChange::ACTION_UPDATE: |
575 if (current_machine_tag() == session.session_tag()) { | 573 if (current_machine_tag() == session.session_tag()) { |
576 // We should only ever receive a change to our own machine's session | 574 // We should only ever receive a change to our own machine's session |
577 // info if encryption was turned on. In that case, the data is still | 575 // info if encryption was turned on. In that case, the data is still |
578 // the same, so we can ignore. | 576 // the same, so we can ignore. |
579 LOG(WARNING) << "Dropping modification to local session."; | 577 LOG(WARNING) << "Dropping modification to local session."; |
580 return syncer::SyncError(); | 578 return syncer::SyncError(); |
581 } | 579 } |
582 UpdateTrackerWithForeignSession( | 580 UpdateTrackerWithSpecifics( |
583 session, syncer::SyncDataRemote(it->sync_data()).GetModifiedTime()); | 581 session, syncer::SyncDataRemote(it->sync_data()).GetModifiedTime()); |
584 break; | 582 break; |
585 default: | 583 default: |
586 NOTREACHED() << "Processing sync changes failed, unknown change type."; | 584 NOTREACHED() << "Processing sync changes failed, unknown change type."; |
587 } | 585 } |
588 } | 586 } |
589 | 587 |
590 if (!sessions_updated_callback_.is_null()) | 588 if (!sessions_updated_callback_.is_null()) |
591 sessions_updated_callback_.Run(); | 589 sessions_updated_callback_.Run(); |
592 return syncer::SyncError(); | 590 return syncer::SyncError(); |
593 } | 591 } |
594 | 592 |
595 syncer::SyncChange SessionsSyncManager::TombstoneTab( | 593 syncer::SyncChange SessionsSyncManager::TombstoneTab( |
596 const sync_pb::SessionSpecifics& tab) { | 594 const sync_pb::SessionSpecifics& tab) { |
597 if (!tab.has_tab_node_id()) { | 595 if (!tab.has_tab_node_id()) { |
598 LOG(WARNING) << "Old sessions node without tab node id; can't tombstone."; | 596 LOG(WARNING) << "Old sessions node without tab node id; can't tombstone."; |
599 return syncer::SyncChange(); | 597 return syncer::SyncChange(); |
600 } else { | 598 } else { |
601 return syncer::SyncChange( | 599 return syncer::SyncChange( |
602 FROM_HERE, SyncChange::ACTION_DELETE, | 600 FROM_HERE, SyncChange::ACTION_DELETE, |
603 SyncData::CreateLocalDelete( | 601 SyncData::CreateLocalDelete( |
604 TabNodePool::TabIdToTag(current_machine_tag(), tab.tab_node_id()), | 602 TabNodeIdToTag(current_machine_tag(), tab.tab_node_id()), |
605 syncer::SESSIONS)); | 603 syncer::SESSIONS)); |
606 } | 604 } |
607 } | 605 } |
608 | 606 |
609 bool SessionsSyncManager::GetAllForeignSessions( | 607 bool SessionsSyncManager::GetAllForeignSessions( |
610 std::vector<const SyncedSession*>* sessions) { | 608 std::vector<const SyncedSession*>* sessions) { |
611 if (!session_tracker_.LookupAllForeignSessions( | 609 if (!session_tracker_.LookupAllForeignSessions( |
612 sessions, SyncedSessionTracker::PRESENTABLE)) | 610 sessions, SyncedSessionTracker::PRESENTABLE)) |
613 return false; | 611 return false; |
614 std::sort(sessions->begin(), sessions->end(), SessionsRecencyComparator); | 612 std::sort(sessions->begin(), sessions->end(), SessionsRecencyComparator); |
615 return true; | 613 return true; |
616 } | 614 } |
617 | 615 |
618 bool SessionsSyncManager::InitFromSyncModel( | 616 bool SessionsSyncManager::InitFromSyncModel( |
619 const syncer::SyncDataList& sync_data, | 617 const syncer::SyncDataList& sync_data, |
620 syncer::SyncDataList* restored_tabs, | |
621 syncer::SyncChangeList* new_changes) { | 618 syncer::SyncChangeList* new_changes) { |
622 bool found_current_header = false; | 619 bool found_current_header = false; |
623 int bad_foreign_hash_count = 0; | 620 int bad_foreign_hash_count = 0; |
624 for (syncer::SyncDataList::const_iterator it = sync_data.begin(); | 621 for (syncer::SyncDataList::const_iterator it = sync_data.begin(); |
625 it != sync_data.end(); ++it) { | 622 it != sync_data.end(); ++it) { |
626 const syncer::SyncData& data = *it; | 623 const syncer::SyncData& data = *it; |
627 DCHECK(data.GetSpecifics().has_session()); | 624 DCHECK(data.GetSpecifics().has_session()); |
628 syncer::SyncDataRemote remote(data); | 625 syncer::SyncDataRemote remote(data); |
629 const sync_pb::SessionSpecifics& specifics = data.GetSpecifics().session(); | 626 const sync_pb::SessionSpecifics& specifics = data.GetSpecifics().session(); |
630 if (specifics.session_tag().empty() || | 627 if (specifics.session_tag().empty() || |
631 (specifics.has_tab() && | 628 (specifics.has_tab() && |
632 (!specifics.has_tab_node_id() || !specifics.tab().has_tab_id()))) { | 629 (!specifics.has_tab_node_id() || !specifics.tab().has_tab_id()))) { |
633 syncer::SyncChange tombstone(TombstoneTab(specifics)); | 630 syncer::SyncChange tombstone(TombstoneTab(specifics)); |
634 if (tombstone.IsValid()) | 631 if (tombstone.IsValid()) |
635 new_changes->push_back(tombstone); | 632 new_changes->push_back(tombstone); |
636 } else if (specifics.session_tag() != current_machine_tag()) { | 633 } else if (specifics.session_tag() != current_machine_tag()) { |
637 if (TagHashFromSpecifics(specifics) == remote.GetClientTagHash()) { | 634 if (TagHashFromSpecifics(specifics) == remote.GetClientTagHash()) { |
638 UpdateTrackerWithForeignSession(specifics, remote.GetModifiedTime()); | 635 UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime()); |
639 } else { | 636 } else { |
640 // In the past, like years ago, we believe that some session data was | 637 // In the past, like years ago, we believe that some session data was |
641 // created with bad tag hashes. This causes any change this client makes | 638 // created with bad tag hashes. This causes any change this client makes |
642 // to that foreign data (like deletion through garbage collection) to | 639 // to that foreign data (like deletion through garbage collection) to |
643 // trigger a data type error because the tag looking mechanism fails. So | 640 // trigger a data type error because the tag looking mechanism fails. So |
644 // look for these and delete via remote SyncData, which uses a server id | 641 // look for these and delete via remote SyncData, which uses a server id |
645 // lookup mechanism instead, see crbug.com/604657. | 642 // lookup mechanism instead, see crbug.com/604657. |
646 bad_foreign_hash_count++; | 643 bad_foreign_hash_count++; |
647 new_changes->push_back( | 644 new_changes->push_back( |
648 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, remote)); | 645 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, remote)); |
649 } | 646 } |
650 } else { | 647 } else { |
651 // This is previously stored local session information. | 648 // This is previously stored local session information. |
652 if (specifics.has_header() && !found_current_header) { | 649 if (specifics.has_header() && !found_current_header) { |
653 // This is our previous header node, reuse it. | 650 // This is our previous header node, reuse it. |
654 found_current_header = true; | 651 found_current_header = true; |
655 if (specifics.header().has_client_name()) | 652 if (specifics.header().has_client_name()) |
656 current_session_name_ = specifics.header().client_name(); | 653 current_session_name_ = specifics.header().client_name(); |
654 | |
655 // TODO(zea): crbug.com/639009 update the tracker with the specifics | |
656 // from the header node as well. This will be necessary to preserve | |
657 // the set of open tabs when a custom tab is opened. | |
657 } else { | 658 } else { |
658 if (specifics.has_header() || !specifics.has_tab()) { | 659 if (specifics.has_header() || !specifics.has_tab()) { |
659 LOG(WARNING) << "Found more than one session header node with local " | 660 LOG(WARNING) << "Found more than one session header node with local " |
660 << "tag."; | 661 << "tag."; |
661 syncer::SyncChange tombstone(TombstoneTab(specifics)); | 662 syncer::SyncChange tombstone(TombstoneTab(specifics)); |
662 if (tombstone.IsValid()) | 663 if (tombstone.IsValid()) |
663 new_changes->push_back(tombstone); | 664 new_changes->push_back(tombstone); |
664 } else { | 665 } else { |
665 // This is a valid old tab node, add it to the pool so it can be | 666 // This is a valid old tab node, add it to the tracker and associate |
666 // reused for reassociation. | 667 // it. |
667 local_tab_pool_.AddTabNode(specifics.tab_node_id()); | 668 DVLOG(1) << "Associating local tab " << specifics.tab().tab_id() |
668 restored_tabs->push_back(*it); | 669 << " with node " << specifics.tab_node_id(); |
670 session_tracker_.ReassociateLocalTab(specifics.tab_node_id(), | |
671 specifics.tab().tab_id()); | |
672 UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime()); | |
669 } | 673 } |
670 } | 674 } |
671 } | 675 } |
672 } | 676 } |
673 | 677 |
674 // Cleanup all foreign sessions, since orphaned tabs may have been added after | 678 // Cleanup all foreign sessions, since orphaned tabs may have been added after |
675 // the header. | 679 // the header. |
676 std::vector<const SyncedSession*> sessions; | 680 std::vector<const SyncedSession*> sessions; |
677 session_tracker_.LookupAllForeignSessions(&sessions, | 681 session_tracker_.LookupAllForeignSessions(&sessions, |
678 SyncedSessionTracker::RAW); | 682 SyncedSessionTracker::RAW); |
679 for (const auto* session : sessions) { | 683 for (const auto* session : sessions) { |
680 session_tracker_.CleanupSession(session->session_tag); | 684 session_tracker_.CleanupForeignSession(session->session_tag); |
681 } | 685 } |
682 | 686 |
683 UMA_HISTOGRAM_COUNTS_100("Sync.SessionsBadForeignHashOnMergeCount", | 687 UMA_HISTOGRAM_COUNTS_100("Sync.SessionsBadForeignHashOnMergeCount", |
684 bad_foreign_hash_count); | 688 bad_foreign_hash_count); |
685 | 689 |
686 return found_current_header; | 690 return found_current_header; |
687 } | 691 } |
688 | 692 |
689 void SessionsSyncManager::UpdateTrackerWithForeignSession( | 693 void SessionsSyncManager::UpdateTrackerWithSpecifics( |
690 const sync_pb::SessionSpecifics& specifics, | 694 const sync_pb::SessionSpecifics& specifics, |
691 const base::Time& modification_time) { | 695 const base::Time& modification_time) { |
692 std::string foreign_session_tag = specifics.session_tag(); | 696 std::string session_tag = specifics.session_tag(); |
693 DCHECK_NE(foreign_session_tag, current_machine_tag()); | 697 SyncedSession* session = session_tracker_.GetSession(session_tag); |
694 | |
695 SyncedSession* foreign_session = | |
696 session_tracker_.GetSession(foreign_session_tag); | |
697 if (specifics.has_header()) { | 698 if (specifics.has_header()) { |
698 // Read in the header data for this foreign session. Header data is | 699 // Read in the header data for this session. Header data is |
699 // essentially a collection of windows, each of which has an ordered id list | 700 // essentially a collection of windows, each of which has an ordered id list |
700 // for their tabs. | 701 // for their tabs. |
701 | 702 |
702 if (!IsValidSessionHeader(specifics.header())) { | 703 if (!IsValidSessionHeader(specifics.header())) { |
703 LOG(WARNING) << "Ignoring foreign session node with invalid header " | 704 LOG(WARNING) << "Ignoring session node with invalid header " |
704 << "and tag " << foreign_session_tag << "."; | 705 << "and tag " << session_tag << "."; |
705 return; | 706 return; |
706 } | 707 } |
707 | 708 |
708 // Load (or create) the SyncedSession object for this client. | 709 // Load (or create) the SyncedSession object for this client. |
709 const sync_pb::SessionHeader& header = specifics.header(); | 710 const sync_pb::SessionHeader& header = specifics.header(); |
710 PopulateSessionHeaderFromSpecifics(header, modification_time, | 711 PopulateSessionHeaderFromSpecifics(header, modification_time, session); |
711 foreign_session); | |
712 | 712 |
713 // Reset the tab/window tracking for this session (must do this before | 713 // Reset the tab/window tracking for this session (must do this before |
714 // we start calling PutWindowInSession and PutTabInWindow so that all | 714 // we start calling PutWindowInSession and PutTabInWindow so that all |
715 // unused tabs/windows get cleared by the CleanupSession(...) call). | 715 // unused tabs/windows get cleared by the CleanupSession(...) call). |
716 session_tracker_.ResetSessionTracking(foreign_session_tag); | 716 session_tracker_.ResetSessionTracking(session_tag); |
717 | 717 |
718 // Process all the windows and their tab information. | 718 // Process all the windows and their tab information. |
719 int num_windows = header.window_size(); | 719 int num_windows = header.window_size(); |
720 DVLOG(1) << "Associating " << foreign_session_tag << " with " << num_windows | 720 DVLOG(1) << "Populating " << session_tag << " with " << num_windows |
721 << " windows."; | 721 << " windows."; |
722 | 722 |
723 for (int i = 0; i < num_windows; ++i) { | 723 for (int i = 0; i < num_windows; ++i) { |
724 const sync_pb::SessionWindow& window_s = header.window(i); | 724 const sync_pb::SessionWindow& window_s = header.window(i); |
725 SessionID::id_type window_id = window_s.window_id(); | 725 SessionID::id_type window_id = window_s.window_id(); |
726 session_tracker_.PutWindowInSession(foreign_session_tag, window_id); | 726 session_tracker_.PutWindowInSession(session_tag, window_id); |
727 BuildSyncedSessionFromSpecifics( | 727 BuildSyncedSessionFromSpecifics(session_tag, window_s, modification_time, |
728 foreign_session_tag, window_s, modification_time, | 728 session->windows[window_id].get()); |
729 foreign_session->windows[window_id].get()); | |
730 } | 729 } |
731 // Delete any closed windows and unused tabs as necessary. | 730 // Delete any closed windows and unused tabs as necessary. |
732 session_tracker_.CleanupSession(foreign_session_tag); | 731 session_tracker_.CleanupForeignSession(session_tag); |
733 } else if (specifics.has_tab()) { | 732 } else if (specifics.has_tab()) { |
734 const sync_pb::SessionTab& tab_s = specifics.tab(); | 733 const sync_pb::SessionTab& tab_s = specifics.tab(); |
735 SessionID::id_type tab_id = tab_s.tab_id(); | 734 SessionID::id_type tab_id = tab_s.tab_id(); |
735 DVLOG(1) << "Populating " << session_tag << "'s tab id " << tab_id | |
736 << " from node " << specifics.tab_node_id(); | |
736 | 737 |
737 const sessions::SessionTab* existing_tab; | 738 // Ensure the tracker is aware of the tab node id. Deleting foreign sessions |
738 if (session_tracker_.LookupSessionTab(foreign_session_tag, tab_id, | 739 // requires deleting all relevant tab nodes, and it's easier to track the |
739 &existing_tab) && | 740 // tab node ids themselves separately from the tab ids. |
740 existing_tab->timestamp > modification_time) { | 741 // |
741 // Force the tracker to remember this tab node id, even if it isn't | 742 // Note that TabIDs are not stable across restarts of a client. Consider |
742 // currently being used. | 743 // this example with two tabs: |
743 session_tracker_.GetTab(foreign_session_tag, tab_id, | 744 // |
744 specifics.tab_node_id()); | 745 // http://a.com TabID1 --> NodeIDA |
745 DVLOG(1) << "Ignoring " << foreign_session_tag << "'s session tab " | 746 // http://b.com TabID2 --> NodeIDB |
746 << tab_id << " with earlier modification time"; | 747 // |
748 // After restart, tab ids are reallocated. e.g, one possibility: | |
749 // http://a.com TabID2 --> NodeIDA | |
750 // http://b.com TabID1 --> NodeIDB | |
751 // | |
752 // If that happened on a remote client, here we will see an update to | |
753 // TabID1 with tab_node_id changing from NodeIDA to NodeIDB, and TabID2 | |
754 // with tab_node_id changing from NodeIDB to NodeIDA. | |
755 // | |
756 // We can also wind up here if we created this tab as an out-of-order | |
757 // update to the header node for this session before actually associating | |
758 // the tab itself, so the tab node id wasn't available at the time and | |
759 // is currently kInvalidTabNodeID. | |
760 // | |
761 // In both cases, we can safely throw it into the set of node ids. | |
762 session_tracker_.OnTabNodeSeen(session_tag, specifics.tab_node_id()); | |
763 sessions::SessionTab* tab = session_tracker_.GetTab(session_tag, tab_id); | |
764 if (!tab->timestamp.is_null() && tab->timestamp > modification_time) { | |
765 DVLOG(1) << "Ignoring " << session_tag << "'s session tab " << tab_id | |
766 << " with earlier modification time: " << tab->timestamp | |
767 << " vs " << modification_time; | |
747 return; | 768 return; |
748 } | 769 } |
749 | 770 |
750 sessions::SessionTab* tab = session_tracker_.GetTab( | |
751 foreign_session_tag, tab_id, specifics.tab_node_id()); | |
752 | |
753 // Update SessionTab based on protobuf. | 771 // Update SessionTab based on protobuf. |
754 tab->SetFromSyncData(tab_s, modification_time); | 772 tab->SetFromSyncData(tab_s, modification_time); |
755 | 773 |
756 // If a favicon or favicon urls are present, load the URLs and visit | 774 // If a favicon or favicon urls are present, load the URLs and visit |
757 // times into the in-memory favicon cache. | 775 // times into the in-memory favicon cache. |
758 RefreshFaviconVisitTimesFromForeignTab(tab_s, modification_time); | 776 RefreshFaviconVisitTimesFromForeignTab(tab_s, modification_time); |
759 | 777 |
760 // Update the last modified time. | 778 // Update the last modified time. |
761 if (foreign_session->modified_time < modification_time) | 779 if (session->modified_time < modification_time) |
762 foreign_session->modified_time = modification_time; | 780 session->modified_time = modification_time; |
763 } else { | 781 } else { |
764 LOG(WARNING) << "Ignoring foreign session node with missing header/tab " | 782 LOG(WARNING) << "Ignoring session node with missing header/tab " |
765 << "fields and tag " << foreign_session_tag << "."; | 783 << "fields and tag " << session_tag << "."; |
766 } | 784 } |
767 } | 785 } |
768 | 786 |
769 void SessionsSyncManager::InitializeCurrentMachineTag( | 787 void SessionsSyncManager::InitializeCurrentMachineTag( |
770 const std::string& cache_guid) { | 788 const std::string& cache_guid) { |
771 DCHECK(current_machine_tag_.empty()); | 789 DCHECK(current_machine_tag_.empty()); |
772 std::string persisted_guid; | 790 std::string persisted_guid; |
773 persisted_guid = sync_prefs_->GetSyncSessionsGUID(); | 791 persisted_guid = sync_prefs_->GetSyncSessionsGUID(); |
774 if (!persisted_guid.empty()) { | 792 if (!persisted_guid.empty()) { |
775 current_machine_tag_ = persisted_guid; | 793 current_machine_tag_ = persisted_guid; |
776 DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid; | 794 DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid; |
777 } else { | 795 } else { |
778 DCHECK(!cache_guid.empty()); | 796 DCHECK(!cache_guid.empty()); |
779 current_machine_tag_ = BuildMachineTag(cache_guid); | 797 current_machine_tag_ = BuildMachineTag(cache_guid); |
780 DVLOG(1) << "Creating session sync guid: " << current_machine_tag_; | 798 DVLOG(1) << "Creating session sync guid: " << current_machine_tag_; |
781 sync_prefs_->SetSyncSessionsGUID(current_machine_tag_); | 799 sync_prefs_->SetSyncSessionsGUID(current_machine_tag_); |
782 } | 800 } |
783 | |
784 local_tab_pool_.SetMachineTag(current_machine_tag_); | |
785 } | 801 } |
786 | 802 |
787 // static | 803 // static |
788 void SessionsSyncManager::PopulateSessionHeaderFromSpecifics( | 804 void SessionsSyncManager::PopulateSessionHeaderFromSpecifics( |
789 const sync_pb::SessionHeader& header_specifics, | 805 const sync_pb::SessionHeader& header_specifics, |
790 base::Time mtime, | 806 base::Time mtime, |
791 SyncedSession* session_header) { | 807 SyncedSession* session_header) { |
792 if (header_specifics.has_client_name()) | 808 if (header_specifics.has_client_name()) |
793 session_header->session_name = header_specifics.client_name(); | 809 session_header->session_name = header_specifics.client_name(); |
794 if (header_specifics.has_device_type()) { | 810 if (header_specifics.has_device_type()) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
838 if (specifics.browser_type() == | 854 if (specifics.browser_type() == |
839 sync_pb::SessionWindow_BrowserType_TYPE_TABBED) { | 855 sync_pb::SessionWindow_BrowserType_TYPE_TABBED) { |
840 session_window->type = sessions::SessionWindow::TYPE_TABBED; | 856 session_window->type = sessions::SessionWindow::TYPE_TABBED; |
841 } else { | 857 } else { |
842 // Note: custom tabs are treated like popup windows on restore, as you can | 858 // Note: custom tabs are treated like popup windows on restore, as you can |
843 // restore a custom tab on a platform that doesn't support them. | 859 // restore a custom tab on a platform that doesn't support them. |
844 session_window->type = sessions::SessionWindow::TYPE_POPUP; | 860 session_window->type = sessions::SessionWindow::TYPE_POPUP; |
845 } | 861 } |
846 } | 862 } |
847 session_window->timestamp = mtime; | 863 session_window->timestamp = mtime; |
848 session_window->tabs.resize(specifics.tab_size()); | 864 session_window->tabs.clear(); |
849 for (int i = 0; i < specifics.tab_size(); i++) { | 865 for (int i = 0; i < specifics.tab_size(); i++) { |
850 SessionID::id_type tab_id = specifics.tab(i); | 866 SessionID::id_type tab_id = specifics.tab(i); |
851 session_tracker_.PutTabInWindow(session_tag, session_window->window_id.id(), | 867 session_tracker_.PutTabInWindow(session_tag, session_window->window_id.id(), |
852 tab_id, i); | 868 tab_id); |
853 } | 869 } |
854 } | 870 } |
855 | 871 |
856 void SessionsSyncManager::RefreshFaviconVisitTimesFromForeignTab( | 872 void SessionsSyncManager::RefreshFaviconVisitTimesFromForeignTab( |
857 const sync_pb::SessionTab& tab, | 873 const sync_pb::SessionTab& tab, |
858 const base::Time& modification_time) { | 874 const base::Time& modification_time) { |
859 // First go through and iterate over all the navigations, checking if any | 875 // First go through and iterate over all the navigations, checking if any |
860 // have valid favicon urls. | 876 // have valid favicon urls. |
861 for (int i = 0; i < tab.navigation_size(); ++i) { | 877 for (int i = 0; i < tab.navigation_size(); ++i) { |
862 if (!tab.navigation(i).favicon_url().empty()) { | 878 if (!tab.navigation(i).favicon_url().empty()) { |
(...skipping 21 matching lines...) Expand all Loading... | |
884 void SessionsSyncManager::DeleteForeignSessionInternal( | 900 void SessionsSyncManager::DeleteForeignSessionInternal( |
885 const std::string& tag, | 901 const std::string& tag, |
886 syncer::SyncChangeList* change_output) { | 902 syncer::SyncChangeList* change_output) { |
887 if (tag == current_machine_tag()) { | 903 if (tag == current_machine_tag()) { |
888 LOG(ERROR) << "Attempting to delete local session. This is not currently " | 904 LOG(ERROR) << "Attempting to delete local session. This is not currently " |
889 << "supported."; | 905 << "supported."; |
890 return; | 906 return; |
891 } | 907 } |
892 | 908 |
893 std::set<int> tab_node_ids_to_delete; | 909 std::set<int> tab_node_ids_to_delete; |
894 session_tracker_.LookupTabNodeIds(tag, &tab_node_ids_to_delete); | 910 session_tracker_.LookupForeignTabNodeIds(tag, &tab_node_ids_to_delete); |
895 if (DisassociateForeignSession(tag)) { | 911 if (DisassociateForeignSession(tag)) { |
896 // Only tell sync to delete the header if there was one. | 912 // Only tell sync to delete the header if there was one. |
897 change_output->push_back( | 913 change_output->push_back( |
898 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, | 914 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, |
899 SyncData::CreateLocalDelete(tag, syncer::SESSIONS))); | 915 SyncData::CreateLocalDelete(tag, syncer::SESSIONS))); |
900 } | 916 } |
901 for (std::set<int>::const_iterator it = tab_node_ids_to_delete.begin(); | 917 for (std::set<int>::const_iterator it = tab_node_ids_to_delete.begin(); |
902 it != tab_node_ids_to_delete.end(); ++it) { | 918 it != tab_node_ids_to_delete.end(); ++it) { |
903 change_output->push_back(syncer::SyncChange( | 919 change_output->push_back( |
904 FROM_HERE, SyncChange::ACTION_DELETE, | 920 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, |
905 SyncData::CreateLocalDelete(TabNodePool::TabIdToTag(tag, *it), | 921 SyncData::CreateLocalDelete(TabNodeIdToTag(tag, *it), |
906 syncer::SESSIONS))); | 922 syncer::SESSIONS))); |
907 } | 923 } |
908 if (!sessions_updated_callback_.is_null()) | 924 if (!sessions_updated_callback_.is_null()) |
909 sessions_updated_callback_.Run(); | 925 sessions_updated_callback_.Run(); |
910 } | 926 } |
911 | 927 |
912 bool SessionsSyncManager::DisassociateForeignSession( | 928 bool SessionsSyncManager::DisassociateForeignSession( |
913 const std::string& foreign_session_tag) { | 929 const std::string& foreign_session_tag) { |
914 DCHECK_NE(foreign_session_tag, current_machine_tag()); | 930 DCHECK_NE(foreign_session_tag, current_machine_tag()); |
915 DVLOG(1) << "Disassociating session " << foreign_session_tag; | 931 DVLOG(1) << "Disassociating session " << foreign_session_tag; |
916 return session_tracker_.DeleteSession(foreign_session_tag); | 932 return session_tracker_.DeleteForeignSession(foreign_session_tag); |
917 } | 933 } |
918 | 934 |
919 bool SessionsSyncManager::GetForeignSession( | 935 bool SessionsSyncManager::GetForeignSession( |
920 const std::string& tag, | 936 const std::string& tag, |
921 std::vector<const sessions::SessionWindow*>* windows) { | 937 std::vector<const sessions::SessionWindow*>* windows) { |
922 return session_tracker_.LookupSessionWindows(tag, windows); | 938 return session_tracker_.LookupSessionWindows(tag, windows); |
923 } | 939 } |
924 | 940 |
925 bool SessionsSyncManager::GetForeignSessionTabs( | 941 bool SessionsSyncManager::GetForeignSessionTabs( |
926 const std::string& tag, | 942 const std::string& tag, |
(...skipping 25 matching lines...) Expand all Loading... | |
952 bool SessionsSyncManager::GetForeignTab(const std::string& tag, | 968 bool SessionsSyncManager::GetForeignTab(const std::string& tag, |
953 const SessionID::id_type tab_id, | 969 const SessionID::id_type tab_id, |
954 const sessions::SessionTab** tab) { | 970 const sessions::SessionTab** tab) { |
955 const sessions::SessionTab* synced_tab = nullptr; | 971 const sessions::SessionTab* synced_tab = nullptr; |
956 bool success = session_tracker_.LookupSessionTab(tag, tab_id, &synced_tab); | 972 bool success = session_tracker_.LookupSessionTab(tag, tab_id, &synced_tab); |
957 if (success) | 973 if (success) |
958 *tab = synced_tab; | 974 *tab = synced_tab; |
959 return success; | 975 return success; |
960 } | 976 } |
961 | 977 |
962 void SessionsSyncManager::LocalTabDelegateToSpecifics( | |
963 const SyncedTabDelegate& tab_delegate, | |
964 sync_pb::SessionSpecifics* specifics) { | |
965 sessions::SessionTab* session_tab = nullptr; | |
966 session_tab = session_tracker_.GetTab(current_machine_tag(), | |
967 tab_delegate.GetSessionId(), | |
968 tab_delegate.GetSyncId()); | |
969 SetSessionTabFromDelegate(tab_delegate, base::Time::Now(), session_tab); | |
970 SetVariationIds(session_tab); | |
971 sync_pb::SessionTab tab_s = session_tab->ToSyncData(); | |
972 specifics->set_session_tag(current_machine_tag_); | |
973 specifics->set_tab_node_id(tab_delegate.GetSyncId()); | |
974 specifics->mutable_tab()->CopyFrom(tab_s); | |
975 } | |
976 | |
977 void SessionsSyncManager::AssociateRestoredPlaceholderTab( | 978 void SessionsSyncManager::AssociateRestoredPlaceholderTab( |
978 const SyncedTabDelegate& tab_delegate, | 979 const SyncedTabDelegate& tab_delegate, |
979 SessionID::id_type new_tab_id, | 980 SessionID::id_type new_tab_id, |
980 SessionID::id_type new_window_id, | 981 SessionID::id_type new_window_id, |
981 const syncer::SyncDataList& restored_tabs, | |
982 syncer::SyncChangeList* change_output) { | 982 syncer::SyncChangeList* change_output) { |
983 DCHECK_NE(tab_delegate.GetSyncId(), TabNodePool::kInvalidTabNodeID); | 983 DCHECK_NE(tab_delegate.GetSyncId(), TabNodePool::kInvalidTabNodeID); |
984 // Rewrite the tab using |restored_tabs| to retrieve the specifics. | 984 |
985 if (restored_tabs.empty()) { | 985 // It's possible the placeholder tab is associated with a tab node that's |
986 DLOG(WARNING) << "Can't Update tab ID."; | 986 // since been deleted. If that's the case, there's no way to reassociate it, |
987 // so just return now without adding the tab to the session tracker. | |
988 if (!session_tracker_.IsLocalTabNodeValid(tab_delegate.GetSyncId())) { | |
989 DVLOG(1) << "Restored placeholder tab's node " << tab_delegate.GetSyncId() | |
990 << " deleted."; | |
987 return; | 991 return; |
988 } | 992 } |
989 | 993 |
990 for (syncer::SyncDataList::const_iterator it = restored_tabs.begin(); | 994 // Update tracker with the new association (and inform it of the tab node |
991 it != restored_tabs.end(); ++it) { | 995 // in the process). |
992 if (it->GetSpecifics().session().tab_node_id() != | 996 session_tracker_.ReassociateLocalTab(tab_delegate.GetSyncId(), new_tab_id); |
993 tab_delegate.GetSyncId()) { | |
994 continue; | |
995 } | |
996 | 997 |
997 sync_pb::EntitySpecifics entity; | 998 // Update the window id on the SessionTab itself. |
998 sync_pb::SessionSpecifics* specifics = entity.mutable_session(); | 999 sessions::SessionTab* local_tab = |
999 specifics->CopyFrom(it->GetSpecifics().session()); | 1000 session_tracker_.GetTab(current_machine_tag(), new_tab_id); |
1000 DCHECK(specifics->has_tab()); | 1001 local_tab->window_id.set_id(new_window_id); |
1001 | 1002 |
1002 // Update tab node pool with the new association. | 1003 // Rewrite the specifics based on the reassociated SessionTab to preserve |
1003 local_tab_pool_.ReassociateTabNode(tab_delegate.GetSyncId(), new_tab_id); | 1004 // the new tab and window ids. |
1004 TabLink* tab_link = new TabLink(tab_delegate.GetSyncId(), &tab_delegate); | 1005 sync_pb::EntitySpecifics entity; |
1005 local_tab_map_[new_tab_id] = make_linked_ptr<TabLink>(tab_link); | 1006 entity.mutable_session()->CopyFrom(SessionTabToSpecifics( |
1006 | 1007 *local_tab, current_machine_tag(), tab_delegate.GetSyncId())); |
1007 if (specifics->tab().tab_id() == new_tab_id && | 1008 syncer::SyncData data = syncer::SyncData::CreateLocalData( |
1008 specifics->tab().window_id() == new_window_id) | 1009 TabNodeIdToTag(current_machine_tag(), tab_delegate.GetSyncId()), |
1009 return; | 1010 current_session_name_, entity); |
1010 | 1011 change_output->push_back( |
1011 // Either the tab_id or window_id changed (e.g due to session restore), so | 1012 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); |
1012 // update the sync node. | |
1013 specifics->mutable_tab()->set_tab_id(new_tab_id); | |
1014 specifics->mutable_tab()->set_window_id(new_window_id); | |
1015 syncer::SyncData data = syncer::SyncData::CreateLocalData( | |
1016 TabNodePool::TabIdToTag(current_machine_tag_, specifics->tab_node_id()), | |
1017 current_session_name_, entity); | |
1018 change_output->push_back( | |
1019 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); | |
1020 return; | |
1021 } | |
1022 } | 1013 } |
1023 | 1014 |
1024 // static | 1015 // static |
1025 void SessionsSyncManager::SetSessionTabFromDelegate( | 1016 void SessionsSyncManager::SetSessionTabFromDelegate( |
1026 const SyncedTabDelegate& tab_delegate, | 1017 const SyncedTabDelegate& tab_delegate, |
1027 base::Time mtime, | 1018 base::Time mtime, |
1028 sessions::SessionTab* session_tab) { | 1019 sessions::SessionTab* session_tab) { |
1029 DCHECK(session_tab); | 1020 DCHECK(session_tab); |
1030 session_tab->window_id.set_id(tab_delegate.GetWindowId()); | 1021 session_tab->window_id.set_id(tab_delegate.GetWindowId()); |
1031 session_tab->tab_id.set_id(tab_delegate.GetSessionId()); | 1022 session_tab->tab_id.set_id(tab_delegate.GetSessionId()); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1130 } | 1121 } |
1131 | 1122 |
1132 // static | 1123 // static |
1133 std::string SessionsSyncManager::TagHashFromSpecifics( | 1124 std::string SessionsSyncManager::TagHashFromSpecifics( |
1134 const sync_pb::SessionSpecifics& specifics) { | 1125 const sync_pb::SessionSpecifics& specifics) { |
1135 return syncer::GenerateSyncableHash(syncer::SESSIONS, | 1126 return syncer::GenerateSyncableHash(syncer::SESSIONS, |
1136 TagFromSpecifics(specifics)); | 1127 TagFromSpecifics(specifics)); |
1137 } | 1128 } |
1138 | 1129 |
1139 }; // namespace sync_sessions | 1130 }; // namespace sync_sessions |
OLD | NEW |