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