Chromium Code Reviews| Index: components/sync_sessions/sessions_sync_manager.cc |
| diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc |
| index 665929fcd4e255dfcdfab3ccb3a15f5bdfc88130..2b2ba3fb89fc31c26e9094933427295da93de832 100644 |
| --- a/components/sync_sessions/sessions_sync_manager.cc |
| +++ b/components/sync_sessions/sessions_sync_manager.cc |
| @@ -110,6 +110,28 @@ bool ShouldSyncTabId(SessionID::id_type tab_id) { |
| return true; |
| } |
| +SyncedSession::DeviceType ProtoDeviceTypeToSyncedSessionDeviceType( |
| + sync_pb::SyncEnums::DeviceType proto_device_type) { |
| + switch (proto_device_type) { |
| + case sync_pb::SyncEnums_DeviceType_TYPE_WIN: |
| + return SyncedSession::TYPE_WIN; |
| + case sync_pb::SyncEnums_DeviceType_TYPE_MAC: |
| + return SyncedSession::TYPE_MACOSX; |
| + case sync_pb::SyncEnums_DeviceType_TYPE_LINUX: |
| + return SyncedSession::TYPE_LINUX; |
| + case sync_pb::SyncEnums_DeviceType_TYPE_CROS: |
| + return SyncedSession::TYPE_CHROMEOS; |
| + case sync_pb::SyncEnums_DeviceType_TYPE_PHONE: |
| + return SyncedSession::TYPE_PHONE; |
| + case sync_pb::SyncEnums_DeviceType_TYPE_TABLET: |
| + return SyncedSession::TYPE_TABLET; |
| + case sync_pb::SyncEnums_DeviceType_TYPE_OTHER: |
| + // Intentionally fall-through |
|
skym
2017/04/17 20:37:02
Why allow a fall through? Why not have a compile e
Nicolas Zea
2017/04/17 21:24:54
Good call, done.
|
| + default: |
| + return SyncedSession::TYPE_OTHER; |
| + } |
| +} |
| + |
| } // namespace |
| // |local_device| is owned by ProfileSyncService, its lifetime exceeds |
| @@ -229,115 +251,154 @@ syncer::SyncMergeResult SessionsSyncManager::MergeDataAndStartSyncing( |
| void SessionsSyncManager::AssociateWindows( |
| ReloadTabsOption option, |
| syncer::SyncChangeList* change_output) { |
| - const std::string local_tag = current_machine_tag(); |
| - sync_pb::SessionSpecifics specifics; |
| - specifics.set_session_tag(local_tag); |
| - sync_pb::SessionHeader* header_s = specifics.mutable_header(); |
| - SyncedSession* current_session = session_tracker_.GetSession(local_tag); |
| - current_session->modified_time = base::Time::Now(); |
| - header_s->set_client_name(current_session_name_); |
| - header_s->set_device_type(current_device_type_); |
| + // Note that |current_session| is a pointer owned by |session_tracker_|. |
| + // |session_tracker_| will continue to update |current_session| under |
| + // the hood, e.g. during ResetSessionTracking(..), so care must be taken |
|
skym
2017/04/17 20:37:02
I don't understand what this means and how you're
Nicolas Zea
2017/04/17 21:24:54
Expanded the comment to clarify. ResetSessionTrack
|
| + // accessing it. |
| + SyncedSession* current_session = |
| + session_tracker_.GetSession(current_machine_tag()); |
| + current_session->session_name = current_session_name_; |
| + current_session->device_type = |
| + ProtoDeviceTypeToSyncedSessionDeviceType(current_device_type_); |
| + current_session->session_tag = current_machine_tag(); |
| - session_tracker_.ResetSessionTracking(local_tag); |
| SyncedWindowDelegatesGetter::SyncedWindowDelegateMap windows = |
| synced_window_delegates_getter()->GetSyncedWindowDelegates(); |
| - if (option == RELOAD_TABS) { |
| - UMA_HISTOGRAM_COUNTS("Sync.SessionWindows", windows.size()); |
| + // On Android, it's possible to not have any tabbed windows if this is a cold |
| + // start triggered for a custom tab. In that case, the previous session must |
| + // be restored, otherwise it will be lost. On the other hand, if there is at |
| + // least one tabbed window open, it's safe to overwrite the previous session |
| + // entirely. See crbug.com/639009 for more info. |
| + bool found_tabbed_window = false; |
| + for (auto& window_iter_pair : windows) { |
| + if (window_iter_pair.second->IsTypeTabbed()) |
| + found_tabbed_window = true; |
| } |
| - if (windows.size() == 0) { |
| - // Assume that the window hasn't loaded. Attempting to associate now would |
| - // clobber any old windows, so just return. |
| - LOG(ERROR) << "No windows present, see crbug.com/639009"; |
| - return; |
| + |
| + if (found_tabbed_window) { |
| + // Just reset the session tracking. No need to worry about the previous |
| + // session; the current tabbed windows are now the source of truth. |
| + session_tracker_.ResetSessionTracking(current_machine_tag()); |
| + current_session->modified_time = base::Time::Now(); |
| + } else { |
| + DVLOG(1) << "Found no tabbed windows. Reloading " |
| + << current_session->windows.size() |
| + << " windows from previous session."; |
| + |
| + // A copy of the specifics must be made because |current_session| will be |
| + // updated in place and therefore can't be relied on as the source of truth. |
| + sync_pb::SessionHeader header_specifics; |
| + header_specifics.CopyFrom(current_session->ToSessionHeaderProto()); |
| + session_tracker_.ResetSessionTracking(current_machine_tag()); |
| + PopulateSyncedSessionFromSpecifics(current_machine_tag(), header_specifics, |
| + base::Time::Now(), current_session); |
| + |
| + // The tab entities stored in sync have outdated SessionId values. Go |
| + // through and update them to the new SessionIds. |
| + for (auto& win_iter : current_session->windows) { |
| + for (auto& tab : win_iter.second->wrapped_window.tabs) { |
| + int sync_id = TabNodePool::kInvalidTabNodeID; |
| + if (!session_tracker_.GetTabNodeFromLocalTabId(tab->tab_id.id(), |
| + &sync_id) || |
| + sync_id == TabNodePool::kInvalidTabNodeID) { |
| + continue; |
| + } |
| + DVLOG(1) << "Rewriting tab node " << sync_id << " with tab id " |
| + << tab->tab_id.id(); |
| + UpdateTabSpecifics(sync_id, *tab, change_output); |
| + } |
| + } |
| } |
| - for (auto window_iter_pair : windows) { |
| + |
| + for (auto& window_iter_pair : windows) { |
| const SyncedWindowDelegate* window_delegate = window_iter_pair.second; |
| if (option == RELOAD_TABS) { |
| UMA_HISTOGRAM_COUNTS("Sync.SessionTabs", window_delegate->GetTabCount()); |
| } |
| - // Make sure the window has tabs and a viewable window. The viewable window |
| - // check is necessary because, for example, when a browser is closed the |
| - // destructor is not necessarily run immediately. This means its possible |
| - // for us to get a handle to a browser that is about to be removed. If |
| - // the tab count is 0 or the window is null, the browser is about to be |
| - // deleted, so we ignore it. |
| + // Make sure the window has tabs and a viewable window. The viewable |
| + // window check is necessary because, for example, when a browser is |
| + // closed the destructor is not necessarily run immediately. This means |
| + // its possible for us to get a handle to a browser that is about to be |
| + // removed. If the tab count is 0 or the window is null, the browser is |
| + // about to be deleted, so we ignore it. |
| if (window_delegate->ShouldSync() && window_delegate->GetTabCount() && |
| window_delegate->HasWindow()) { |
| sync_pb::SessionWindow window_s; |
| SessionID::id_type window_id = window_delegate->GetSessionId(); |
| DVLOG(1) << "Associating window " << window_id << " with " |
| << window_delegate->GetTabCount() << " tabs."; |
| - window_s.set_window_id(window_id); |
| - // Note: We don't bother to set selected tab index anymore. We still |
| - // consume it when receiving foreign sessions, as reading it is free, but |
| - // it triggers too many sync cycles with too little value to make setting |
| - // it worthwhile. |
| - if (window_delegate->IsTypeTabbed()) { |
| - window_s.set_browser_type( |
| - sync_pb::SessionWindow_BrowserType_TYPE_TABBED); |
| - } else if (window_delegate->IsTypePopup()) { |
| - window_s.set_browser_type( |
| - sync_pb::SessionWindow_BrowserType_TYPE_POPUP); |
| - } else { |
| - // This is a custom tab within an app. These will not be restored on |
| - // startup if not present. |
| - window_s.set_browser_type( |
| - sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB); |
| - } |
| bool found_tabs = false; |
| for (int j = 0; j < window_delegate->GetTabCount(); ++j) { |
| SessionID::id_type tab_id = window_delegate->GetTabIdAt(j); |
| SyncedTabDelegate* synced_tab = window_delegate->GetTabAt(j); |
| - // GetTabAt can return a null tab; in that case just skip it. |
| - if (!synced_tab) |
| - continue; |
| - |
| - if (!ShouldSyncTabId(tab_id)) { |
| - LOG(ERROR) << "Not syncing invalid tab with id " << tab_id; |
| + // GetTabAt can return a null tab; in that case just skip it. Similarly, |
| + // if for some reason the tab id is invalid, skip it. |
| + if (!synced_tab || !ShouldSyncTabId(tab_id)) |
| continue; |
| - } |
| // Placeholder tabs are those without WebContents, either because they |
| // were never loaded into memory or they were evicted from memory |
| - // (typically only on Android devices). They only have a tab id, window |
| - // id, and a saved synced id (corresponding to the tab node id). Note |
| - // that only placeholders have this sync id, as it's necessary to |
| - // properly reassociate the tab with the entity that was backing it. |
| + // (typically only on Android devices). They only have a tab id, |
| + // window id, and a saved synced id (corresponding to the tab node |
| + // id). Note that only placeholders have this sync id, as it's |
| + // necessary to properly reassociate the tab with the entity that was |
| + // backing it. |
| if (synced_tab->IsPlaceholderTab()) { |
| // For tabs without WebContents update the |tab_id| and |window_id|, |
| // as it could have changed after a session restore. |
| if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID) { |
| AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id, |
| change_output); |
| + } else { |
| + DVLOG(1) << "Placeholder tab " << tab_id << " has no sync id."; |
| } |
| } else if (RELOAD_TABS == option) { |
| AssociateTab(synced_tab, change_output); |
| } |
| // If the tab was syncable, it would have been added to the tracker |
| - // either by the above Associate[RestoredPlaceholder]Tab call or by the |
| - // OnLocalTabModified method invoking AssociateTab directly. Therefore, |
| - // we can key whether this window has valid tabs based on the tab's |
| - // presence in the tracker. |
| + // either by the above Associate[RestoredPlaceholder]Tab call or by |
| + // the OnLocalTabModified method invoking AssociateTab directly. |
| + // Therefore, we can key whether this window has valid tabs based on |
| + // the tab's presence in the tracker. |
| const sessions::SessionTab* tab = nullptr; |
| - if (session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) { |
| + if (session_tracker_.LookupSessionTab(current_machine_tag(), tab_id, |
| + &tab)) { |
| found_tabs = true; |
| - window_s.add_tab(tab_id); |
| + |
| + // Update this window's representation in the synced session tracker. |
| + // This is a no-op if called multiple times. |
| + session_tracker_.PutWindowInSession(current_machine_tag(), window_id); |
| + |
| + // Put the tab in the window (must happen after the window is added |
| + // to the session). |
| + session_tracker_.PutTabInWindow(current_machine_tag(), window_id, |
| + tab_id); |
| } |
| } |
| if (found_tabs) { |
| - sync_pb::SessionWindow* header_window = header_s->add_window(); |
| - *header_window = window_s; |
| - |
| - // Update this window's representation in the synced session tracker. |
| - session_tracker_.PutWindowInSession(local_tag, window_id); |
| - BuildSyncedSessionFromSpecifics( |
| - local_tag, window_s, current_session->modified_time, |
| - current_session->windows[window_id].get()); |
| + SyncedSessionWindow* synced_session_window = |
| + current_session->windows[window_id].get(); |
| + // Note: We don't bother to set selected tab index anymore. We still |
|
skym
2017/04/17 20:37:02
Seems like we should ideally be able to stop commi
Nicolas Zea
2017/04/17 21:24:54
This comment is out of date actually (was copied o
|
| + // consume it when receiving foreign sessions, as reading it is free, |
| + // but it triggers too many sync cycles with too little value to make |
| + // setting it worthwhile. |
| + if (window_delegate->IsTypeTabbed()) { |
| + synced_session_window->window_type = |
| + sync_pb::SessionWindow_BrowserType_TYPE_TABBED; |
| + } else if (window_delegate->IsTypePopup()) { |
| + synced_session_window->window_type = |
| + sync_pb::SessionWindow_BrowserType_TYPE_POPUP; |
| + } else { |
| + // This is a custom tab within an app. These will not be restored on |
| + // startup if not present. |
| + synced_session_window->window_type = |
| + sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB; |
| + } |
| } |
| } |
| } |
| @@ -350,7 +411,9 @@ void SessionsSyncManager::AssociateWindows( |
| // if the entity specifics are identical (i.e windows, client name did |
| // not change). |
| sync_pb::EntitySpecifics entity; |
| - entity.mutable_session()->CopyFrom(specifics); |
| + entity.mutable_session()->set_session_tag(current_machine_tag()); |
| + entity.mutable_session()->mutable_header()->CopyFrom( |
| + current_session->ToSessionHeaderProto()); |
| syncer::SyncData data = syncer::SyncData::CreateLocalData( |
| current_machine_tag(), current_session_name_, entity); |
| change_output->push_back( |
| @@ -375,10 +438,17 @@ void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab_delegate, |
| << tab_delegate->GetWindowId(); |
| int tab_node_id = TabNodePool::kInvalidTabNodeID; |
| - bool existing_tab_node = |
| - session_tracker_.GetTabNodeFromLocalTabId(tab_id, &tab_node_id); |
| - CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id) << "crbug.com/673618"; |
| - tab_delegate->SetSyncId(tab_node_id); |
| + bool existing_tab_node = true; |
| + if (session_tracker_.IsLocalTabNodeAssociated(tab_delegate->GetSyncId())) { |
| + tab_node_id = tab_delegate->GetSyncId(); |
| + session_tracker_.ReassociateLocalTab(tab_node_id, tab_id); |
| + } else { |
| + existing_tab_node = |
| + session_tracker_.GetTabNodeFromLocalTabId(tab_id, &tab_node_id); |
| + CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id) << "crbug.com/673618"; |
| + tab_delegate->SetSyncId(tab_node_id); |
| + } |
| + |
| sessions::SessionTab* session_tab = |
| session_tracker_.GetTab(current_machine_tag(), tab_id); |
| @@ -633,6 +703,12 @@ bool SessionsSyncManager::GetAllForeignSessions( |
| bool SessionsSyncManager::InitFromSyncModel( |
| const syncer::SyncDataList& sync_data, |
| syncer::SyncChangeList* new_changes) { |
| + // Map of all rewritten local ids. Because ids are reset on each restart, |
| + // and id generation happens outside of Sync, all ids from a previous local |
| + // session must be rewritten in order to be valid. |
| + // Key: previous session id. Value: new session id. |
| + std::map<SessionID::id_type, SessionID::id_type> session_id_map; |
| + |
| bool found_current_header = false; |
| int bad_foreign_hash_count = 0; |
| for (syncer::SyncDataList::const_iterator it = sync_data.begin(); |
| @@ -669,9 +745,35 @@ bool SessionsSyncManager::InitFromSyncModel( |
| if (specifics.header().has_client_name()) |
| current_session_name_ = specifics.header().client_name(); |
| - // TODO(zea): crbug.com/639009 update the tracker with the specifics |
| - // from the header node as well. This will be necessary to preserve |
| - // the set of open tabs when a custom tab is opened. |
| + // The specifics from the SyncData are immutable. Create a mutable copy |
| + // to hold the rewritten ids. |
| + sync_pb::SessionSpecifics rewritten_specifics(specifics); |
| + |
| + // Go through and generate new tab and window ids as necessary, updating |
| + // the specifics in place. |
| + for (auto& window : |
| + *rewritten_specifics.mutable_header()->mutable_window()) { |
| + session_id_map[window.window_id()] = SessionID().id(); |
| + window.set_window_id(session_id_map[window.window_id()]); |
| + |
| + google::protobuf::RepeatedField<int>* tab_ids = window.mutable_tab(); |
| + for (int i = 0; i < tab_ids->size(); i++) { |
| + auto tab_iter = session_id_map.find(tab_ids->Get(i)); |
| + if (tab_iter == session_id_map.end()) { |
| + session_id_map[tab_ids->Get(i)] = SessionID().id(); |
|
skym
2017/04/17 20:37:02
I was really confused by this SessionID call until
Nicolas Zea
2017/04/17 21:24:54
Yeah, I know what you mean. Added a comment to mak
|
| + } |
| + *(tab_ids->Mutable(i)) = session_id_map[tab_ids->Get(i)]; |
| + // Note: the tab id of the SessionTab will be updated when the tab |
| + // node itself is processed. |
| + } |
| + } |
| + |
| + UpdateTrackerWithSpecifics(rewritten_specifics, |
| + remote.GetModifiedTime()); |
| + |
| + DVLOG(1) << "Loaded local header and rewrote " << session_id_map.size() |
| + << " ids."; |
| + |
| } else { |
| if (specifics.has_header() || !specifics.has_tab()) { |
| LOG(WARNING) << "Found more than one session header node with local " |
| @@ -686,12 +788,33 @@ bool SessionsSyncManager::InitFromSyncModel( |
| new_changes->push_back(tombstone); |
| } else { |
| // This is a valid old tab node, add it to the tracker and associate |
| - // it. |
| + // it (using the new tab id). |
| DVLOG(1) << "Associating local tab " << specifics.tab().tab_id() |
| << " with node " << specifics.tab_node_id(); |
| - session_tracker_.ReassociateLocalTab(specifics.tab_node_id(), |
| - specifics.tab().tab_id()); |
| - UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime()); |
| + |
| + // Now file the tab under the new tab id. |
| + SessionID::id_type new_tab_id = kInvalidTabID; |
| + auto iter = session_id_map.find(specifics.tab().tab_id()); |
| + if (iter != session_id_map.end()) { |
| + new_tab_id = iter->second; |
| + } else { |
| + session_id_map[specifics.tab().tab_id()] = SessionID().id(); |
| + new_tab_id = session_id_map[specifics.tab().tab_id()]; |
| + } |
| + DVLOG(1) << "Remapping tab " << specifics.tab().tab_id() << " to " |
| + << new_tab_id; |
| + |
| + // The specifics from the SyncData are immutable. Create a mutable |
| + // copy to hold the rewritten ids. |
| + sync_pb::SessionSpecifics rewritten_specifics(specifics); |
| + rewritten_specifics.mutable_tab()->set_tab_id(new_tab_id); |
| + session_tracker_.ReassociateLocalTab( |
| + rewritten_specifics.tab_node_id(), new_tab_id); |
| + UpdateTrackerWithSpecifics(rewritten_specifics, |
| + remote.GetModifiedTime()); |
| + |
| + session_tracker_.ReassociateLocalTab( |
| + rewritten_specifics.tab_node_id(), new_tab_id); |
| } |
| } |
| } |
| @@ -703,7 +826,7 @@ bool SessionsSyncManager::InitFromSyncModel( |
| session_tracker_.LookupAllForeignSessions(&sessions, |
| SyncedSessionTracker::RAW); |
| for (const auto* session : sessions) { |
| - session_tracker_.CleanupForeignSession(session->session_tag); |
| + session_tracker_.CleanupSession(session->session_tag); |
| } |
| UMA_HISTOGRAM_COUNTS_100("Sync.SessionsBadForeignHashOnMergeCount", |
| @@ -730,27 +853,17 @@ void SessionsSyncManager::UpdateTrackerWithSpecifics( |
| // Load (or create) the SyncedSession object for this client. |
| const sync_pb::SessionHeader& header = specifics.header(); |
| - PopulateSessionHeaderFromSpecifics(header, modification_time, session); |
| // Reset the tab/window tracking for this session (must do this before |
| // we start calling PutWindowInSession and PutTabInWindow so that all |
| // unused tabs/windows get cleared by the CleanupSession(...) call). |
| session_tracker_.ResetSessionTracking(session_tag); |
| - // Process all the windows and their tab information. |
| - int num_windows = header.window_size(); |
| - DVLOG(1) << "Populating " << session_tag << " with " << num_windows |
| - << " windows."; |
| - |
| - for (int i = 0; i < num_windows; ++i) { |
| - const sync_pb::SessionWindow& window_s = header.window(i); |
| - SessionID::id_type window_id = window_s.window_id(); |
| - session_tracker_.PutWindowInSession(session_tag, window_id); |
| - BuildSyncedSessionFromSpecifics(session_tag, window_s, modification_time, |
| - session->windows[window_id].get()); |
| - } |
| + PopulateSyncedSessionFromSpecifics(session_tag, header, modification_time, |
| + session); |
| + |
| // Delete any closed windows and unused tabs as necessary. |
| - session_tracker_.CleanupForeignSession(session_tag); |
| + session_tracker_.CleanupSession(session_tag); |
| } else if (specifics.has_tab()) { |
| const sync_pb::SessionTab& tab_s = specifics.tab(); |
| SessionID::id_type tab_id = tab_s.tab_id(); |
| @@ -822,46 +935,37 @@ void SessionsSyncManager::InitializeCurrentMachineTag( |
| } |
| } |
| -// static |
| -void SessionsSyncManager::PopulateSessionHeaderFromSpecifics( |
| +void SessionsSyncManager::PopulateSyncedSessionFromSpecifics( |
| + const std::string& session_tag, |
| const sync_pb::SessionHeader& header_specifics, |
| base::Time mtime, |
| - SyncedSession* session_header) { |
| + SyncedSession* synced_session) { |
| if (header_specifics.has_client_name()) |
| - session_header->session_name = header_specifics.client_name(); |
| + synced_session->session_name = header_specifics.client_name(); |
| if (header_specifics.has_device_type()) { |
| - switch (header_specifics.device_type()) { |
| - case sync_pb::SyncEnums_DeviceType_TYPE_WIN: |
| - session_header->device_type = SyncedSession::TYPE_WIN; |
| - break; |
| - case sync_pb::SyncEnums_DeviceType_TYPE_MAC: |
| - session_header->device_type = SyncedSession::TYPE_MACOSX; |
| - break; |
| - case sync_pb::SyncEnums_DeviceType_TYPE_LINUX: |
| - session_header->device_type = SyncedSession::TYPE_LINUX; |
| - break; |
| - case sync_pb::SyncEnums_DeviceType_TYPE_CROS: |
| - session_header->device_type = SyncedSession::TYPE_CHROMEOS; |
| - break; |
| - case sync_pb::SyncEnums_DeviceType_TYPE_PHONE: |
| - session_header->device_type = SyncedSession::TYPE_PHONE; |
| - break; |
| - case sync_pb::SyncEnums_DeviceType_TYPE_TABLET: |
| - session_header->device_type = SyncedSession::TYPE_TABLET; |
| - break; |
| - case sync_pb::SyncEnums_DeviceType_TYPE_OTHER: |
| - // Intentionally fall-through |
| - default: |
| - session_header->device_type = SyncedSession::TYPE_OTHER; |
| - break; |
| - } |
| + synced_session->device_type = ProtoDeviceTypeToSyncedSessionDeviceType( |
| + header_specifics.device_type()); |
| + } |
| + synced_session->modified_time = |
| + std::max(mtime, synced_session->modified_time); |
| + |
| + // Process all the windows and their tab information. |
| + int num_windows = header_specifics.window_size(); |
| + DVLOG(1) << "Populating " << session_tag << " with " << num_windows |
| + << " windows."; |
| + |
| + for (int i = 0; i < num_windows; ++i) { |
| + const sync_pb::SessionWindow& window_s = header_specifics.window(i); |
| + SessionID::id_type window_id = window_s.window_id(); |
| + session_tracker_.PutWindowInSession(session_tag, window_id); |
| + PopulateSyncedSessionWindowFromSpecifics( |
| + session_tag, window_s, synced_session->modified_time, |
| + synced_session->windows[window_id].get()); |
| } |
| - session_header->modified_time = |
| - std::max(mtime, session_header->modified_time); |
| } |
| // static |
| -void SessionsSyncManager::BuildSyncedSessionFromSpecifics( |
| +void SessionsSyncManager::PopulateSyncedSessionWindowFromSpecifics( |
| const std::string& session_tag, |
| const sync_pb::SessionWindow& specifics, |
| base::Time mtime, |
| @@ -1017,14 +1121,21 @@ void SessionsSyncManager::AssociateRestoredPlaceholderTab( |
| session_tracker_.GetTab(current_machine_tag(), new_tab_id); |
| local_tab->window_id.set_id(new_window_id); |
| + UpdateTabSpecifics(tab_delegate.GetSyncId(), *local_tab, change_output); |
| +} |
| + |
| +void SessionsSyncManager::UpdateTabSpecifics( |
| + int sync_id, |
| + const sessions::SessionTab& tab, |
| + syncer::SyncChangeList* change_output) { |
| // Rewrite the specifics based on the reassociated SessionTab to preserve |
| // the new tab and window ids. |
| sync_pb::EntitySpecifics entity; |
| - entity.mutable_session()->CopyFrom(SessionTabToSpecifics( |
| - *local_tab, current_machine_tag(), tab_delegate.GetSyncId())); |
| + entity.mutable_session()->CopyFrom( |
| + SessionTabToSpecifics(tab, current_machine_tag(), sync_id)); |
| syncer::SyncData data = syncer::SyncData::CreateLocalData( |
| - TabNodeIdToTag(current_machine_tag(), tab_delegate.GetSyncId()), |
| - current_session_name_, entity); |
| + TabNodeIdToTag(current_machine_tag(), sync_id), current_session_name_, |
| + entity); |
| change_output->push_back( |
| syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); |
| } |