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" | 10 #include "base/format_macros.h" |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 } | 103 } |
104 } | 104 } |
105 | 105 |
106 // Ensure that the tab id is not invalid. | 106 // Ensure that the tab id is not invalid. |
107 bool ShouldSyncTabId(SessionID::id_type tab_id) { | 107 bool ShouldSyncTabId(SessionID::id_type tab_id) { |
108 if (tab_id == kInvalidTabID) | 108 if (tab_id == kInvalidTabID) |
109 return false; | 109 return false; |
110 return true; | 110 return true; |
111 } | 111 } |
112 | 112 |
| 113 SyncedSession::DeviceType ProtoDeviceTypeToSyncedSessionDeviceType( |
| 114 sync_pb::SyncEnums::DeviceType proto_device_type) { |
| 115 switch (proto_device_type) { |
| 116 case sync_pb::SyncEnums_DeviceType_TYPE_WIN: |
| 117 return SyncedSession::TYPE_WIN; |
| 118 case sync_pb::SyncEnums_DeviceType_TYPE_MAC: |
| 119 return SyncedSession::TYPE_MACOSX; |
| 120 case sync_pb::SyncEnums_DeviceType_TYPE_LINUX: |
| 121 return SyncedSession::TYPE_LINUX; |
| 122 case sync_pb::SyncEnums_DeviceType_TYPE_CROS: |
| 123 return SyncedSession::TYPE_CHROMEOS; |
| 124 case sync_pb::SyncEnums_DeviceType_TYPE_PHONE: |
| 125 return SyncedSession::TYPE_PHONE; |
| 126 case sync_pb::SyncEnums_DeviceType_TYPE_TABLET: |
| 127 return SyncedSession::TYPE_TABLET; |
| 128 case sync_pb::SyncEnums_DeviceType_TYPE_OTHER: |
| 129 return SyncedSession::TYPE_OTHER; |
| 130 } |
| 131 return SyncedSession::TYPE_OTHER; |
| 132 } |
| 133 |
113 } // namespace | 134 } // namespace |
114 | 135 |
115 // |local_device| is owned by ProfileSyncService, its lifetime exceeds | 136 // |local_device| is owned by ProfileSyncService, its lifetime exceeds |
116 // lifetime of SessionSyncManager. | 137 // lifetime of SessionSyncManager. |
117 SessionsSyncManager::SessionsSyncManager( | 138 SessionsSyncManager::SessionsSyncManager( |
118 sync_sessions::SyncSessionsClient* sessions_client, | 139 sync_sessions::SyncSessionsClient* sessions_client, |
119 syncer::SyncPrefs* sync_prefs, | 140 syncer::SyncPrefs* sync_prefs, |
120 LocalDeviceInfoProvider* local_device, | 141 LocalDeviceInfoProvider* local_device, |
121 LocalSessionEventRouter* router, | 142 LocalSessionEventRouter* router, |
122 const base::Closure& sessions_updated_callback, | 143 const base::Closure& sessions_updated_callback, |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 merge_result.set_error( | 243 merge_result.set_error( |
223 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); | 244 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); |
224 | 245 |
225 local_event_router_->StartRoutingTo(this); | 246 local_event_router_->StartRoutingTo(this); |
226 return merge_result; | 247 return merge_result; |
227 } | 248 } |
228 | 249 |
229 void SessionsSyncManager::AssociateWindows( | 250 void SessionsSyncManager::AssociateWindows( |
230 ReloadTabsOption option, | 251 ReloadTabsOption option, |
231 syncer::SyncChangeList* change_output) { | 252 syncer::SyncChangeList* change_output) { |
232 const std::string local_tag = current_machine_tag(); | 253 // Note that |current_session| is a pointer owned by |session_tracker_|. |
233 sync_pb::SessionSpecifics specifics; | 254 // |session_tracker_| will continue to update |current_session| under |
234 specifics.set_session_tag(local_tag); | 255 // the hood so care must be taken accessing it. In particular, invoking |
235 sync_pb::SessionHeader* header_s = specifics.mutable_header(); | 256 // ResetSessionTracking(..) will invalidate all the tab data within |
236 SyncedSession* current_session = session_tracker_.GetSession(local_tag); | 257 // the session, hence why copies of the SyncedSession must be made ahead of |
237 current_session->modified_time = base::Time::Now(); | 258 // time. |
238 header_s->set_client_name(current_session_name_); | 259 SyncedSession* current_session = |
239 header_s->set_device_type(current_device_type_); | 260 session_tracker_.GetSession(current_machine_tag()); |
| 261 current_session->session_name = current_session_name_; |
| 262 current_session->device_type = |
| 263 ProtoDeviceTypeToSyncedSessionDeviceType(current_device_type_); |
| 264 current_session->session_tag = current_machine_tag(); |
240 | 265 |
241 session_tracker_.ResetSessionTracking(local_tag); | |
242 SyncedWindowDelegatesGetter::SyncedWindowDelegateMap windows = | 266 SyncedWindowDelegatesGetter::SyncedWindowDelegateMap windows = |
243 synced_window_delegates_getter()->GetSyncedWindowDelegates(); | 267 synced_window_delegates_getter()->GetSyncedWindowDelegates(); |
244 | 268 |
245 if (option == RELOAD_TABS) { | 269 // On Android, it's possible to not have any tabbed windows if this is a cold |
246 UMA_HISTOGRAM_COUNTS("Sync.SessionWindows", windows.size()); | 270 // start triggered for a custom tab. In that case, the previous session must |
| 271 // be restored, otherwise it will be lost. On the other hand, if there is at |
| 272 // least one tabbed window open, it's safe to overwrite the previous session |
| 273 // entirely. See crbug.com/639009 for more info. |
| 274 bool found_tabbed_window = false; |
| 275 for (auto& window_iter_pair : windows) { |
| 276 if (window_iter_pair.second->IsTypeTabbed()) |
| 277 found_tabbed_window = true; |
247 } | 278 } |
248 if (windows.size() == 0) { | 279 |
249 // Assume that the window hasn't loaded. Attempting to associate now would | 280 if (found_tabbed_window) { |
250 // clobber any old windows, so just return. | 281 // Just reset the session tracking. No need to worry about the previous |
251 LOG(ERROR) << "No windows present, see crbug.com/639009"; | 282 // session; the current tabbed windows are now the source of truth. |
252 return; | 283 session_tracker_.ResetSessionTracking(current_machine_tag()); |
| 284 current_session->modified_time = base::Time::Now(); |
| 285 } else { |
| 286 DVLOG(1) << "Found no tabbed windows. Reloading " |
| 287 << current_session->windows.size() |
| 288 << " windows from previous session."; |
| 289 |
| 290 // A copy of the specifics must be made because |current_session| will be |
| 291 // updated in place and therefore can't be relied on as the source of truth. |
| 292 sync_pb::SessionHeader header_specifics; |
| 293 header_specifics.CopyFrom(current_session->ToSessionHeaderProto()); |
| 294 session_tracker_.ResetSessionTracking(current_machine_tag()); |
| 295 PopulateSyncedSessionFromSpecifics(current_machine_tag(), header_specifics, |
| 296 base::Time::Now(), current_session); |
| 297 |
| 298 // The tab entities stored in sync have outdated SessionId values. Go |
| 299 // through and update them to the new SessionIds. |
| 300 for (auto& win_iter : current_session->windows) { |
| 301 for (auto& tab : win_iter.second->wrapped_window.tabs) { |
| 302 int sync_id = TabNodePool::kInvalidTabNodeID; |
| 303 if (!session_tracker_.GetTabNodeFromLocalTabId(tab->tab_id.id(), |
| 304 &sync_id) || |
| 305 sync_id == TabNodePool::kInvalidTabNodeID) { |
| 306 continue; |
| 307 } |
| 308 DVLOG(1) << "Rewriting tab node " << sync_id << " with tab id " |
| 309 << tab->tab_id.id(); |
| 310 AppendChangeForExistingTab(sync_id, *tab, change_output); |
| 311 } |
| 312 } |
253 } | 313 } |
254 for (auto window_iter_pair : windows) { | 314 |
| 315 for (auto& window_iter_pair : windows) { |
255 const SyncedWindowDelegate* window_delegate = window_iter_pair.second; | 316 const SyncedWindowDelegate* window_delegate = window_iter_pair.second; |
256 if (option == RELOAD_TABS) { | 317 if (option == RELOAD_TABS) { |
257 UMA_HISTOGRAM_COUNTS("Sync.SessionTabs", window_delegate->GetTabCount()); | 318 UMA_HISTOGRAM_COUNTS("Sync.SessionTabs", window_delegate->GetTabCount()); |
258 } | 319 } |
259 | 320 |
260 // Make sure the window has tabs and a viewable window. The viewable window | 321 // Make sure the window has tabs and a viewable window. The viewable |
261 // check is necessary because, for example, when a browser is closed the | 322 // window check is necessary because, for example, when a browser is |
262 // destructor is not necessarily run immediately. This means its possible | 323 // closed the destructor is not necessarily run immediately. This means |
263 // for us to get a handle to a browser that is about to be removed. If | 324 // its possible for us to get a handle to a browser that is about to be |
264 // the tab count is 0 or the window is null, the browser is about to be | 325 // removed. If the tab count is 0 or the window is null, the browser is |
265 // deleted, so we ignore it. | 326 // about to be deleted, so we ignore it. |
266 if (window_delegate->ShouldSync() && window_delegate->GetTabCount() && | 327 if (window_delegate->ShouldSync() && window_delegate->GetTabCount() && |
267 window_delegate->HasWindow()) { | 328 window_delegate->HasWindow()) { |
268 sync_pb::SessionWindow window_s; | 329 sync_pb::SessionWindow window_s; |
269 SessionID::id_type window_id = window_delegate->GetSessionId(); | 330 SessionID::id_type window_id = window_delegate->GetSessionId(); |
270 DVLOG(1) << "Associating window " << window_id << " with " | 331 DVLOG(1) << "Associating window " << window_id << " with " |
271 << window_delegate->GetTabCount() << " tabs."; | 332 << window_delegate->GetTabCount() << " tabs."; |
272 window_s.set_window_id(window_id); | |
273 // Note: We don't bother to set selected tab index anymore. We still | |
274 // consume it when receiving foreign sessions, as reading it is free, but | |
275 // it triggers too many sync cycles with too little value to make setting | |
276 // it worthwhile. | |
277 if (window_delegate->IsTypeTabbed()) { | |
278 window_s.set_browser_type( | |
279 sync_pb::SessionWindow_BrowserType_TYPE_TABBED); | |
280 } else if (window_delegate->IsTypePopup()) { | |
281 window_s.set_browser_type( | |
282 sync_pb::SessionWindow_BrowserType_TYPE_POPUP); | |
283 } else { | |
284 // This is a custom tab within an app. These will not be restored on | |
285 // startup if not present. | |
286 window_s.set_browser_type( | |
287 sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB); | |
288 } | |
289 | 333 |
290 bool found_tabs = false; | 334 bool found_tabs = false; |
291 for (int j = 0; j < window_delegate->GetTabCount(); ++j) { | 335 for (int j = 0; j < window_delegate->GetTabCount(); ++j) { |
292 SessionID::id_type tab_id = window_delegate->GetTabIdAt(j); | 336 SessionID::id_type tab_id = window_delegate->GetTabIdAt(j); |
293 SyncedTabDelegate* synced_tab = window_delegate->GetTabAt(j); | 337 SyncedTabDelegate* synced_tab = window_delegate->GetTabAt(j); |
294 | 338 |
295 // GetTabAt can return a null tab; in that case just skip it. | 339 // GetTabAt can return a null tab; in that case just skip it. Similarly, |
296 if (!synced_tab) | 340 // if for some reason the tab id is invalid, skip it. |
| 341 if (!synced_tab || !ShouldSyncTabId(tab_id)) |
297 continue; | 342 continue; |
298 | 343 |
299 if (!ShouldSyncTabId(tab_id)) { | |
300 LOG(ERROR) << "Not syncing invalid tab with id " << tab_id; | |
301 continue; | |
302 } | |
303 | |
304 // Placeholder tabs are those without WebContents, either because they | 344 // Placeholder tabs are those without WebContents, either because they |
305 // were never loaded into memory or they were evicted from memory | 345 // were never loaded into memory or they were evicted from memory |
306 // (typically only on Android devices). They only have a tab id, window | 346 // (typically only on Android devices). They only have a tab id, |
307 // id, and a saved synced id (corresponding to the tab node id). Note | 347 // window id, and a saved synced id (corresponding to the tab node |
308 // that only placeholders have this sync id, as it's necessary to | 348 // id). Note that only placeholders have this sync id, as it's |
309 // properly reassociate the tab with the entity that was backing it. | 349 // necessary to properly reassociate the tab with the entity that was |
| 350 // backing it. |
310 if (synced_tab->IsPlaceholderTab()) { | 351 if (synced_tab->IsPlaceholderTab()) { |
311 // For tabs without WebContents update the |tab_id| and |window_id|, | 352 // For tabs without WebContents update the |tab_id| and |window_id|, |
312 // as it could have changed after a session restore. | 353 // as it could have changed after a session restore. |
313 if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID) { | 354 if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID) { |
314 AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id, | 355 AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id, |
315 change_output); | 356 change_output); |
| 357 } else { |
| 358 DVLOG(1) << "Placeholder tab " << tab_id << " has no sync id."; |
316 } | 359 } |
317 } else if (RELOAD_TABS == option) { | 360 } else if (RELOAD_TABS == option) { |
318 AssociateTab(synced_tab, change_output); | 361 AssociateTab(synced_tab, change_output); |
319 } | 362 } |
320 | 363 |
321 // If the tab was syncable, it would have been added to the tracker | 364 // If the tab was syncable, it would have been added to the tracker |
322 // either by the above Associate[RestoredPlaceholder]Tab call or by the | 365 // either by the above Associate[RestoredPlaceholder]Tab call or by |
323 // OnLocalTabModified method invoking AssociateTab directly. Therefore, | 366 // the OnLocalTabModified method invoking AssociateTab directly. |
324 // we can key whether this window has valid tabs based on the tab's | 367 // Therefore, we can key whether this window has valid tabs based on |
325 // presence in the tracker. | 368 // the tab's presence in the tracker. |
326 const sessions::SessionTab* tab = nullptr; | 369 const sessions::SessionTab* tab = nullptr; |
327 if (session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) { | 370 if (session_tracker_.LookupSessionTab(current_machine_tag(), tab_id, |
| 371 &tab)) { |
328 found_tabs = true; | 372 found_tabs = true; |
329 window_s.add_tab(tab_id); | 373 |
| 374 // Update this window's representation in the synced session tracker. |
| 375 // This is a no-op if called multiple times. |
| 376 session_tracker_.PutWindowInSession(current_machine_tag(), window_id); |
| 377 |
| 378 // Put the tab in the window (must happen after the window is added |
| 379 // to the session). |
| 380 session_tracker_.PutTabInWindow(current_machine_tag(), window_id, |
| 381 tab_id); |
330 } | 382 } |
331 } | 383 } |
332 if (found_tabs) { | 384 if (found_tabs) { |
333 sync_pb::SessionWindow* header_window = header_s->add_window(); | 385 SyncedSessionWindow* synced_session_window = |
334 *header_window = window_s; | 386 current_session->windows[window_id].get(); |
335 | 387 if (window_delegate->IsTypeTabbed()) { |
336 // Update this window's representation in the synced session tracker. | 388 synced_session_window->window_type = |
337 session_tracker_.PutWindowInSession(local_tag, window_id); | 389 sync_pb::SessionWindow_BrowserType_TYPE_TABBED; |
338 BuildSyncedSessionFromSpecifics( | 390 } else if (window_delegate->IsTypePopup()) { |
339 local_tag, window_s, current_session->modified_time, | 391 synced_session_window->window_type = |
340 current_session->windows[window_id].get()); | 392 sync_pb::SessionWindow_BrowserType_TYPE_POPUP; |
| 393 } else { |
| 394 // This is a custom tab within an app. These will not be restored on |
| 395 // startup if not present. |
| 396 synced_session_window->window_type = |
| 397 sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB; |
| 398 } |
341 } | 399 } |
342 } | 400 } |
343 } | 401 } |
344 std::set<int> deleted_tab_node_ids; | 402 std::set<int> deleted_tab_node_ids; |
345 session_tracker_.CleanupLocalTabs(&deleted_tab_node_ids); | 403 session_tracker_.CleanupLocalTabs(&deleted_tab_node_ids); |
346 AppendDeletionsForTabNodes(deleted_tab_node_ids, current_machine_tag(), | 404 AppendDeletionsForTabNodes(deleted_tab_node_ids, current_machine_tag(), |
347 change_output); | 405 change_output); |
348 | 406 |
349 // Always update the header. Sync takes care of dropping this update | 407 // Always update the header. Sync takes care of dropping this update |
350 // if the entity specifics are identical (i.e windows, client name did | 408 // if the entity specifics are identical (i.e windows, client name did |
351 // not change). | 409 // not change). |
352 sync_pb::EntitySpecifics entity; | 410 sync_pb::EntitySpecifics entity; |
353 entity.mutable_session()->CopyFrom(specifics); | 411 entity.mutable_session()->set_session_tag(current_machine_tag()); |
| 412 entity.mutable_session()->mutable_header()->CopyFrom( |
| 413 current_session->ToSessionHeaderProto()); |
354 syncer::SyncData data = syncer::SyncData::CreateLocalData( | 414 syncer::SyncData data = syncer::SyncData::CreateLocalData( |
355 current_machine_tag(), current_session_name_, entity); | 415 current_machine_tag(), current_session_name_, entity); |
356 change_output->push_back( | 416 change_output->push_back( |
357 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); | 417 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); |
358 } | 418 } |
359 | 419 |
360 void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab_delegate, | 420 void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab_delegate, |
361 syncer::SyncChangeList* change_output) { | 421 syncer::SyncChangeList* change_output) { |
362 DCHECK(!tab_delegate->IsPlaceholderTab()); | 422 DCHECK(!tab_delegate->IsPlaceholderTab()); |
363 | 423 |
364 if (tab_delegate->IsBeingDestroyed()) { | 424 if (tab_delegate->IsBeingDestroyed()) { |
365 // Do nothing. By not proactively adding the tab to the session, it will be | 425 // Do nothing. By not proactively adding the tab to the session, it will be |
366 // removed if necessary during subsequent cleanup. | 426 // removed if necessary during subsequent cleanup. |
367 return; | 427 return; |
368 } | 428 } |
369 | 429 |
370 if (!tab_delegate->ShouldSync(sessions_client_)) | 430 if (!tab_delegate->ShouldSync(sessions_client_)) |
371 return; | 431 return; |
372 | 432 |
373 SessionID::id_type tab_id = tab_delegate->GetSessionId(); | 433 SessionID::id_type tab_id = tab_delegate->GetSessionId(); |
374 DVLOG(1) << "Syncing tab " << tab_id << " from window " | 434 DVLOG(1) << "Syncing tab " << tab_id << " from window " |
375 << tab_delegate->GetWindowId(); | 435 << tab_delegate->GetWindowId(); |
376 | 436 |
377 int tab_node_id = TabNodePool::kInvalidTabNodeID; | 437 int tab_node_id = TabNodePool::kInvalidTabNodeID; |
378 bool existing_tab_node = | 438 bool existing_tab_node = true; |
379 session_tracker_.GetTabNodeFromLocalTabId(tab_id, &tab_node_id); | 439 if (session_tracker_.IsLocalTabNodeAssociated(tab_delegate->GetSyncId())) { |
380 CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id) << "crbug.com/673618"; | 440 tab_node_id = tab_delegate->GetSyncId(); |
381 tab_delegate->SetSyncId(tab_node_id); | 441 session_tracker_.ReassociateLocalTab(tab_node_id, tab_id); |
| 442 } else { |
| 443 existing_tab_node = |
| 444 session_tracker_.GetTabNodeFromLocalTabId(tab_id, &tab_node_id); |
| 445 CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id) << "crbug.com/673618"; |
| 446 tab_delegate->SetSyncId(tab_node_id); |
| 447 } |
| 448 |
382 sessions::SessionTab* session_tab = | 449 sessions::SessionTab* session_tab = |
383 session_tracker_.GetTab(current_machine_tag(), tab_id); | 450 session_tracker_.GetTab(current_machine_tag(), tab_id); |
384 | 451 |
385 // Get the previously synced url. | 452 // Get the previously synced url. |
386 int old_index = session_tab->normalized_navigation_index(); | 453 int old_index = session_tab->normalized_navigation_index(); |
387 GURL old_url; | 454 GURL old_url; |
388 if (session_tab->navigations.size() > static_cast<size_t>(old_index)) | 455 if (session_tab->navigations.size() > static_cast<size_t>(old_index)) |
389 old_url = session_tab->navigations[old_index].virtual_url(); | 456 old_url = session_tab->navigations[old_index].virtual_url(); |
390 | 457 |
391 // Update the tracker's session representation. | 458 // Update the tracker's session representation. |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
626 if (!session_tracker_.LookupAllForeignSessions( | 693 if (!session_tracker_.LookupAllForeignSessions( |
627 sessions, SyncedSessionTracker::PRESENTABLE)) | 694 sessions, SyncedSessionTracker::PRESENTABLE)) |
628 return false; | 695 return false; |
629 std::sort(sessions->begin(), sessions->end(), SessionsRecencyComparator); | 696 std::sort(sessions->begin(), sessions->end(), SessionsRecencyComparator); |
630 return true; | 697 return true; |
631 } | 698 } |
632 | 699 |
633 bool SessionsSyncManager::InitFromSyncModel( | 700 bool SessionsSyncManager::InitFromSyncModel( |
634 const syncer::SyncDataList& sync_data, | 701 const syncer::SyncDataList& sync_data, |
635 syncer::SyncChangeList* new_changes) { | 702 syncer::SyncChangeList* new_changes) { |
| 703 // Map of all rewritten local ids. Because ids are reset on each restart, |
| 704 // and id generation happens outside of Sync, all ids from a previous local |
| 705 // session must be rewritten in order to be valid. |
| 706 // Key: previous session id. Value: new session id. |
| 707 std::map<SessionID::id_type, SessionID::id_type> session_id_map; |
| 708 |
636 bool found_current_header = false; | 709 bool found_current_header = false; |
637 int bad_foreign_hash_count = 0; | 710 int bad_foreign_hash_count = 0; |
638 for (syncer::SyncDataList::const_iterator it = sync_data.begin(); | 711 for (syncer::SyncDataList::const_iterator it = sync_data.begin(); |
639 it != sync_data.end(); ++it) { | 712 it != sync_data.end(); ++it) { |
640 const syncer::SyncData& data = *it; | 713 const syncer::SyncData& data = *it; |
641 DCHECK(data.GetSpecifics().has_session()); | 714 DCHECK(data.GetSpecifics().has_session()); |
642 syncer::SyncDataRemote remote(data); | 715 syncer::SyncDataRemote remote(data); |
643 const sync_pb::SessionSpecifics& specifics = data.GetSpecifics().session(); | 716 const sync_pb::SessionSpecifics& specifics = data.GetSpecifics().session(); |
644 if (specifics.session_tag().empty() || | 717 if (specifics.session_tag().empty() || |
645 (specifics.has_tab() && | 718 (specifics.has_tab() && |
(...skipping 16 matching lines...) Expand all Loading... |
662 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, remote)); | 735 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, remote)); |
663 } | 736 } |
664 } else { | 737 } else { |
665 // This is previously stored local session information. | 738 // This is previously stored local session information. |
666 if (specifics.has_header() && !found_current_header) { | 739 if (specifics.has_header() && !found_current_header) { |
667 // This is our previous header node, reuse it. | 740 // This is our previous header node, reuse it. |
668 found_current_header = true; | 741 found_current_header = true; |
669 if (specifics.header().has_client_name()) | 742 if (specifics.header().has_client_name()) |
670 current_session_name_ = specifics.header().client_name(); | 743 current_session_name_ = specifics.header().client_name(); |
671 | 744 |
672 // TODO(zea): crbug.com/639009 update the tracker with the specifics | 745 // The specifics from the SyncData are immutable. Create a mutable copy |
673 // from the header node as well. This will be necessary to preserve | 746 // to hold the rewritten ids. |
674 // the set of open tabs when a custom tab is opened. | 747 sync_pb::SessionSpecifics rewritten_specifics(specifics); |
| 748 |
| 749 // Go through and generate new tab and window ids as necessary, updating |
| 750 // the specifics in place. |
| 751 for (auto& window : |
| 752 *rewritten_specifics.mutable_header()->mutable_window()) { |
| 753 session_id_map[window.window_id()] = SessionID().id(); |
| 754 window.set_window_id(session_id_map[window.window_id()]); |
| 755 |
| 756 google::protobuf::RepeatedField<int>* tab_ids = window.mutable_tab(); |
| 757 for (int i = 0; i < tab_ids->size(); i++) { |
| 758 auto tab_iter = session_id_map.find(tab_ids->Get(i)); |
| 759 if (tab_iter == session_id_map.end()) { |
| 760 // SessionID::SessionID() automatically increments a static |
| 761 // variable, forcing a new id to be generated each time. |
| 762 session_id_map[tab_ids->Get(i)] = SessionID().id(); |
| 763 } |
| 764 *(tab_ids->Mutable(i)) = session_id_map[tab_ids->Get(i)]; |
| 765 // Note: the tab id of the SessionTab will be updated when the tab |
| 766 // node itself is processed. |
| 767 } |
| 768 } |
| 769 |
| 770 UpdateTrackerWithSpecifics(rewritten_specifics, |
| 771 remote.GetModifiedTime()); |
| 772 |
| 773 DVLOG(1) << "Loaded local header and rewrote " << session_id_map.size() |
| 774 << " ids."; |
| 775 |
675 } else { | 776 } else { |
676 if (specifics.has_header() || !specifics.has_tab()) { | 777 if (specifics.has_header() || !specifics.has_tab()) { |
677 LOG(WARNING) << "Found more than one session header node with local " | 778 LOG(WARNING) << "Found more than one session header node with local " |
678 << "tag."; | 779 << "tag."; |
679 syncer::SyncChange tombstone(TombstoneTab(specifics)); | 780 syncer::SyncChange tombstone(TombstoneTab(specifics)); |
680 if (tombstone.IsValid()) | 781 if (tombstone.IsValid()) |
681 new_changes->push_back(tombstone); | 782 new_changes->push_back(tombstone); |
682 } else if (specifics.tab().tab_id() == kInvalidTabID) { | 783 } else if (specifics.tab().tab_id() == kInvalidTabID) { |
683 LOG(WARNING) << "Found tab node with invalid tab id."; | 784 LOG(WARNING) << "Found tab node with invalid tab id."; |
684 syncer::SyncChange tombstone(TombstoneTab(specifics)); | 785 syncer::SyncChange tombstone(TombstoneTab(specifics)); |
685 if (tombstone.IsValid()) | 786 if (tombstone.IsValid()) |
686 new_changes->push_back(tombstone); | 787 new_changes->push_back(tombstone); |
687 } else { | 788 } else { |
688 // This is a valid old tab node, add it to the tracker and associate | 789 // This is a valid old tab node, add it to the tracker and associate |
689 // it. | 790 // it (using the new tab id). |
690 DVLOG(1) << "Associating local tab " << specifics.tab().tab_id() | 791 DVLOG(1) << "Associating local tab " << specifics.tab().tab_id() |
691 << " with node " << specifics.tab_node_id(); | 792 << " with node " << specifics.tab_node_id(); |
692 session_tracker_.ReassociateLocalTab(specifics.tab_node_id(), | 793 |
693 specifics.tab().tab_id()); | 794 // Now file the tab under the new tab id. |
694 UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime()); | 795 SessionID::id_type new_tab_id = kInvalidTabID; |
| 796 auto iter = session_id_map.find(specifics.tab().tab_id()); |
| 797 if (iter != session_id_map.end()) { |
| 798 new_tab_id = iter->second; |
| 799 } else { |
| 800 session_id_map[specifics.tab().tab_id()] = SessionID().id(); |
| 801 new_tab_id = session_id_map[specifics.tab().tab_id()]; |
| 802 } |
| 803 DVLOG(1) << "Remapping tab " << specifics.tab().tab_id() << " to " |
| 804 << new_tab_id; |
| 805 |
| 806 // The specifics from the SyncData are immutable. Create a mutable |
| 807 // copy to hold the rewritten ids. |
| 808 sync_pb::SessionSpecifics rewritten_specifics(specifics); |
| 809 rewritten_specifics.mutable_tab()->set_tab_id(new_tab_id); |
| 810 session_tracker_.ReassociateLocalTab( |
| 811 rewritten_specifics.tab_node_id(), new_tab_id); |
| 812 UpdateTrackerWithSpecifics(rewritten_specifics, |
| 813 remote.GetModifiedTime()); |
| 814 |
| 815 session_tracker_.ReassociateLocalTab( |
| 816 rewritten_specifics.tab_node_id(), new_tab_id); |
695 } | 817 } |
696 } | 818 } |
697 } | 819 } |
698 } | 820 } |
699 | 821 |
700 // Cleanup all foreign sessions, since orphaned tabs may have been added after | 822 // Cleanup all foreign sessions, since orphaned tabs may have been added after |
701 // the header. | 823 // the header. |
702 std::vector<const SyncedSession*> sessions; | 824 std::vector<const SyncedSession*> sessions; |
703 session_tracker_.LookupAllForeignSessions(&sessions, | 825 session_tracker_.LookupAllForeignSessions(&sessions, |
704 SyncedSessionTracker::RAW); | 826 SyncedSessionTracker::RAW); |
705 for (const auto* session : sessions) { | 827 for (const auto* session : sessions) { |
706 session_tracker_.CleanupForeignSession(session->session_tag); | 828 session_tracker_.CleanupSession(session->session_tag); |
707 } | 829 } |
708 | 830 |
709 UMA_HISTOGRAM_COUNTS_100("Sync.SessionsBadForeignHashOnMergeCount", | 831 UMA_HISTOGRAM_COUNTS_100("Sync.SessionsBadForeignHashOnMergeCount", |
710 bad_foreign_hash_count); | 832 bad_foreign_hash_count); |
711 | 833 |
712 return found_current_header; | 834 return found_current_header; |
713 } | 835 } |
714 | 836 |
715 void SessionsSyncManager::UpdateTrackerWithSpecifics( | 837 void SessionsSyncManager::UpdateTrackerWithSpecifics( |
716 const sync_pb::SessionSpecifics& specifics, | 838 const sync_pb::SessionSpecifics& specifics, |
717 const base::Time& modification_time) { | 839 const base::Time& modification_time) { |
718 std::string session_tag = specifics.session_tag(); | 840 std::string session_tag = specifics.session_tag(); |
719 SyncedSession* session = session_tracker_.GetSession(session_tag); | 841 SyncedSession* session = session_tracker_.GetSession(session_tag); |
720 if (specifics.has_header()) { | 842 if (specifics.has_header()) { |
721 // Read in the header data for this session. Header data is | 843 // Read in the header data for this session. Header data is |
722 // essentially a collection of windows, each of which has an ordered id list | 844 // essentially a collection of windows, each of which has an ordered id list |
723 // for their tabs. | 845 // for their tabs. |
724 | 846 |
725 if (!IsValidSessionHeader(specifics.header())) { | 847 if (!IsValidSessionHeader(specifics.header())) { |
726 LOG(WARNING) << "Ignoring session node with invalid header " | 848 LOG(WARNING) << "Ignoring session node with invalid header " |
727 << "and tag " << session_tag << "."; | 849 << "and tag " << session_tag << "."; |
728 return; | 850 return; |
729 } | 851 } |
730 | 852 |
731 // Load (or create) the SyncedSession object for this client. | 853 // Load (or create) the SyncedSession object for this client. |
732 const sync_pb::SessionHeader& header = specifics.header(); | 854 const sync_pb::SessionHeader& header = specifics.header(); |
733 PopulateSessionHeaderFromSpecifics(header, modification_time, session); | |
734 | 855 |
735 // Reset the tab/window tracking for this session (must do this before | 856 // Reset the tab/window tracking for this session (must do this before |
736 // we start calling PutWindowInSession and PutTabInWindow so that all | 857 // we start calling PutWindowInSession and PutTabInWindow so that all |
737 // unused tabs/windows get cleared by the CleanupSession(...) call). | 858 // unused tabs/windows get cleared by the CleanupSession(...) call). |
738 session_tracker_.ResetSessionTracking(session_tag); | 859 session_tracker_.ResetSessionTracking(session_tag); |
739 | 860 |
740 // Process all the windows and their tab information. | 861 PopulateSyncedSessionFromSpecifics(session_tag, header, modification_time, |
741 int num_windows = header.window_size(); | 862 session); |
742 DVLOG(1) << "Populating " << session_tag << " with " << num_windows | |
743 << " windows."; | |
744 | 863 |
745 for (int i = 0; i < num_windows; ++i) { | |
746 const sync_pb::SessionWindow& window_s = header.window(i); | |
747 SessionID::id_type window_id = window_s.window_id(); | |
748 session_tracker_.PutWindowInSession(session_tag, window_id); | |
749 BuildSyncedSessionFromSpecifics(session_tag, window_s, modification_time, | |
750 session->windows[window_id].get()); | |
751 } | |
752 // Delete any closed windows and unused tabs as necessary. | 864 // Delete any closed windows and unused tabs as necessary. |
753 session_tracker_.CleanupForeignSession(session_tag); | 865 session_tracker_.CleanupSession(session_tag); |
754 } else if (specifics.has_tab()) { | 866 } else if (specifics.has_tab()) { |
755 const sync_pb::SessionTab& tab_s = specifics.tab(); | 867 const sync_pb::SessionTab& tab_s = specifics.tab(); |
756 SessionID::id_type tab_id = tab_s.tab_id(); | 868 SessionID::id_type tab_id = tab_s.tab_id(); |
757 DVLOG(1) << "Populating " << session_tag << "'s tab id " << tab_id | 869 DVLOG(1) << "Populating " << session_tag << "'s tab id " << tab_id |
758 << " from node " << specifics.tab_node_id(); | 870 << " from node " << specifics.tab_node_id(); |
759 | 871 |
760 // Ensure the tracker is aware of the tab node id. Deleting foreign sessions | 872 // Ensure the tracker is aware of the tab node id. Deleting foreign sessions |
761 // requires deleting all relevant tab nodes, and it's easier to track the | 873 // requires deleting all relevant tab nodes, and it's easier to track the |
762 // tab node ids themselves separately from the tab ids. | 874 // tab node ids themselves separately from the tab ids. |
763 // | 875 // |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
815 current_machine_tag_ = persisted_guid; | 927 current_machine_tag_ = persisted_guid; |
816 DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid; | 928 DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid; |
817 } else { | 929 } else { |
818 DCHECK(!cache_guid.empty()); | 930 DCHECK(!cache_guid.empty()); |
819 current_machine_tag_ = BuildMachineTag(cache_guid); | 931 current_machine_tag_ = BuildMachineTag(cache_guid); |
820 DVLOG(1) << "Creating session sync guid: " << current_machine_tag_; | 932 DVLOG(1) << "Creating session sync guid: " << current_machine_tag_; |
821 sync_prefs_->SetSyncSessionsGUID(current_machine_tag_); | 933 sync_prefs_->SetSyncSessionsGUID(current_machine_tag_); |
822 } | 934 } |
823 } | 935 } |
824 | 936 |
| 937 void SessionsSyncManager::PopulateSyncedSessionFromSpecifics( |
| 938 const std::string& session_tag, |
| 939 const sync_pb::SessionHeader& header_specifics, |
| 940 base::Time mtime, |
| 941 SyncedSession* synced_session) { |
| 942 if (header_specifics.has_client_name()) |
| 943 synced_session->session_name = header_specifics.client_name(); |
| 944 if (header_specifics.has_device_type()) { |
| 945 synced_session->device_type = ProtoDeviceTypeToSyncedSessionDeviceType( |
| 946 header_specifics.device_type()); |
| 947 } |
| 948 synced_session->modified_time = |
| 949 std::max(mtime, synced_session->modified_time); |
| 950 |
| 951 // Process all the windows and their tab information. |
| 952 int num_windows = header_specifics.window_size(); |
| 953 DVLOG(1) << "Populating " << session_tag << " with " << num_windows |
| 954 << " windows."; |
| 955 |
| 956 for (int i = 0; i < num_windows; ++i) { |
| 957 const sync_pb::SessionWindow& window_s = header_specifics.window(i); |
| 958 SessionID::id_type window_id = window_s.window_id(); |
| 959 session_tracker_.PutWindowInSession(session_tag, window_id); |
| 960 PopulateSyncedSessionWindowFromSpecifics( |
| 961 session_tag, window_s, synced_session->modified_time, |
| 962 synced_session->windows[window_id].get()); |
| 963 } |
| 964 } |
| 965 |
825 // static | 966 // static |
826 void SessionsSyncManager::PopulateSessionHeaderFromSpecifics( | 967 void SessionsSyncManager::PopulateSyncedSessionWindowFromSpecifics( |
827 const sync_pb::SessionHeader& header_specifics, | |
828 base::Time mtime, | |
829 SyncedSession* session_header) { | |
830 if (header_specifics.has_client_name()) | |
831 session_header->session_name = header_specifics.client_name(); | |
832 if (header_specifics.has_device_type()) { | |
833 switch (header_specifics.device_type()) { | |
834 case sync_pb::SyncEnums_DeviceType_TYPE_WIN: | |
835 session_header->device_type = SyncedSession::TYPE_WIN; | |
836 break; | |
837 case sync_pb::SyncEnums_DeviceType_TYPE_MAC: | |
838 session_header->device_type = SyncedSession::TYPE_MACOSX; | |
839 break; | |
840 case sync_pb::SyncEnums_DeviceType_TYPE_LINUX: | |
841 session_header->device_type = SyncedSession::TYPE_LINUX; | |
842 break; | |
843 case sync_pb::SyncEnums_DeviceType_TYPE_CROS: | |
844 session_header->device_type = SyncedSession::TYPE_CHROMEOS; | |
845 break; | |
846 case sync_pb::SyncEnums_DeviceType_TYPE_PHONE: | |
847 session_header->device_type = SyncedSession::TYPE_PHONE; | |
848 break; | |
849 case sync_pb::SyncEnums_DeviceType_TYPE_TABLET: | |
850 session_header->device_type = SyncedSession::TYPE_TABLET; | |
851 break; | |
852 case sync_pb::SyncEnums_DeviceType_TYPE_OTHER: | |
853 // Intentionally fall-through | |
854 default: | |
855 session_header->device_type = SyncedSession::TYPE_OTHER; | |
856 break; | |
857 } | |
858 } | |
859 session_header->modified_time = | |
860 std::max(mtime, session_header->modified_time); | |
861 } | |
862 | |
863 // static | |
864 void SessionsSyncManager::BuildSyncedSessionFromSpecifics( | |
865 const std::string& session_tag, | 968 const std::string& session_tag, |
866 const sync_pb::SessionWindow& specifics, | 969 const sync_pb::SessionWindow& specifics, |
867 base::Time mtime, | 970 base::Time mtime, |
868 SyncedSessionWindow* synced_session_window) { | 971 SyncedSessionWindow* synced_session_window) { |
869 sessions::SessionWindow* session_window = | 972 sessions::SessionWindow* session_window = |
870 &synced_session_window->wrapped_window; | 973 &synced_session_window->wrapped_window; |
871 if (specifics.has_window_id()) | 974 if (specifics.has_window_id()) |
872 session_window->window_id.set_id(specifics.window_id()); | 975 session_window->window_id.set_id(specifics.window_id()); |
873 if (specifics.has_selected_tab_index()) | 976 if (specifics.has_selected_tab_index()) |
874 session_window->selected_tab_index = specifics.selected_tab_index(); | 977 session_window->selected_tab_index = specifics.selected_tab_index(); |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1010 | 1113 |
1011 // Update tracker with the new association (and inform it of the tab node | 1114 // Update tracker with the new association (and inform it of the tab node |
1012 // in the process). | 1115 // in the process). |
1013 session_tracker_.ReassociateLocalTab(tab_delegate.GetSyncId(), new_tab_id); | 1116 session_tracker_.ReassociateLocalTab(tab_delegate.GetSyncId(), new_tab_id); |
1014 | 1117 |
1015 // Update the window id on the SessionTab itself. | 1118 // Update the window id on the SessionTab itself. |
1016 sessions::SessionTab* local_tab = | 1119 sessions::SessionTab* local_tab = |
1017 session_tracker_.GetTab(current_machine_tag(), new_tab_id); | 1120 session_tracker_.GetTab(current_machine_tag(), new_tab_id); |
1018 local_tab->window_id.set_id(new_window_id); | 1121 local_tab->window_id.set_id(new_window_id); |
1019 | 1122 |
| 1123 AppendChangeForExistingTab(tab_delegate.GetSyncId(), *local_tab, |
| 1124 change_output); |
| 1125 } |
| 1126 |
| 1127 void SessionsSyncManager::AppendChangeForExistingTab( |
| 1128 int sync_id, |
| 1129 const sessions::SessionTab& tab, |
| 1130 syncer::SyncChangeList* change_output) { |
1020 // Rewrite the specifics based on the reassociated SessionTab to preserve | 1131 // Rewrite the specifics based on the reassociated SessionTab to preserve |
1021 // the new tab and window ids. | 1132 // the new tab and window ids. |
1022 sync_pb::EntitySpecifics entity; | 1133 sync_pb::EntitySpecifics entity; |
1023 entity.mutable_session()->CopyFrom(SessionTabToSpecifics( | 1134 entity.mutable_session()->CopyFrom( |
1024 *local_tab, current_machine_tag(), tab_delegate.GetSyncId())); | 1135 SessionTabToSpecifics(tab, current_machine_tag(), sync_id)); |
1025 syncer::SyncData data = syncer::SyncData::CreateLocalData( | 1136 syncer::SyncData data = syncer::SyncData::CreateLocalData( |
1026 TabNodeIdToTag(current_machine_tag(), tab_delegate.GetSyncId()), | 1137 TabNodeIdToTag(current_machine_tag(), sync_id), current_session_name_, |
1027 current_session_name_, entity); | 1138 entity); |
1028 change_output->push_back( | 1139 change_output->push_back( |
1029 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); | 1140 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); |
1030 } | 1141 } |
1031 | 1142 |
1032 // static | 1143 // static |
1033 void SessionsSyncManager::SetSessionTabFromDelegate( | 1144 void SessionsSyncManager::SetSessionTabFromDelegate( |
1034 const SyncedTabDelegate& tab_delegate, | 1145 const SyncedTabDelegate& tab_delegate, |
1035 base::Time mtime, | 1146 base::Time mtime, |
1036 sessions::SessionTab* session_tab) { | 1147 sessions::SessionTab* session_tab) { |
1037 DCHECK(session_tab); | 1148 DCHECK(session_tab); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1126 } | 1237 } |
1127 | 1238 |
1128 // static | 1239 // static |
1129 std::string SessionsSyncManager::TagHashFromSpecifics( | 1240 std::string SessionsSyncManager::TagHashFromSpecifics( |
1130 const sync_pb::SessionSpecifics& specifics) { | 1241 const sync_pb::SessionSpecifics& specifics) { |
1131 return syncer::GenerateSyncableHash(syncer::SESSIONS, | 1242 return syncer::GenerateSyncableHash(syncer::SESSIONS, |
1132 TagFromSpecifics(specifics)); | 1243 TagFromSpecifics(specifics)); |
1133 } | 1244 } |
1134 | 1245 |
1135 }; // namespace sync_sessions | 1246 }; // namespace sync_sessions |
OLD | NEW |