| 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 |