[email protected] | 27684f3 | 2012-04-25 18:28:43 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
zea | c2f678e | 2015-10-28 06:16:10 | [diff] [blame] | 5 | #include "components/sync_sessions/synced_session_tracker.h" |
droger | 6a11863 | 2015-06-23 17:59:45 | [diff] [blame] | 6 | |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 7 | #include <algorithm> |
skym | 6d5ecf8 | 2016-10-04 17:43:45 | [diff] [blame] | 8 | #include <utility> |
| 9 | |
[email protected] | 35d849dc | 2011-10-21 23:49:05 | [diff] [blame] | 10 | #include "base/logging.h" |
[email protected] | e309f31 | 2013-06-07 21:50:08 | [diff] [blame] | 11 | #include "base/strings/utf_string_conversions.h" |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 12 | #include "components/sync/protocol/session_specifics.pb.h" |
zea | f09345c | 2015-10-27 05:29:50 | [diff] [blame] | 13 | #include "components/sync_sessions/sync_sessions_client.h" |
pnoland | 1901afa5 | 2017-03-23 21:24:00 | [diff] [blame] | 14 | #include "components/sync_sessions/synced_tab_delegate.h" |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 15 | |
maxbogue | a79d99b7 | 2016-09-15 15:59:16 | [diff] [blame] | 16 | namespace sync_sessions { |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 17 | |
zea | f09345c | 2015-10-27 05:29:50 | [diff] [blame] | 18 | namespace { |
| 19 | |
| 20 | // Helper for iterating through all tabs within a window, and all navigations |
| 21 | // within a tab, to find if there's a valid syncable url. |
maxbogue | a79d99b7 | 2016-09-15 15:59:16 | [diff] [blame] | 22 | bool ShouldSyncSessionWindow(SyncSessionsClient* sessions_client, |
zea | f09345c | 2015-10-27 05:29:50 | [diff] [blame] | 23 | const sessions::SessionWindow& window) { |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 24 | for (const auto& tab : window.tabs) { |
zea | f09345c | 2015-10-27 05:29:50 | [diff] [blame] | 25 | for (const sessions::SerializedNavigationEntry& navigation : |
| 26 | tab->navigations) { |
| 27 | if (sessions_client->ShouldSyncURL(navigation.virtual_url())) { |
| 28 | return true; |
| 29 | } |
| 30 | } |
| 31 | } |
| 32 | return false; |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 33 | } |
| 34 | |
skym | 199c7fd | 2016-04-14 19:26:42 | [diff] [blame] | 35 | // Presentable means |foreign_session| must have syncable content. |
maxbogue | a79d99b7 | 2016-09-15 15:59:16 | [diff] [blame] | 36 | bool IsPresentable(SyncSessionsClient* sessions_client, |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 37 | const SyncedSession& foreign_session) { |
| 38 | for (auto iter = foreign_session.windows.begin(); |
| 39 | iter != foreign_session.windows.end(); ++iter) { |
zea | 325508e | 2017-03-29 20:11:22 | [diff] [blame] | 40 | if (ShouldSyncSessionWindow(sessions_client, |
| 41 | iter->second->wrapped_window)) { |
skym | 199c7fd | 2016-04-14 19:26:42 | [diff] [blame] | 42 | return true; |
| 43 | } |
| 44 | } |
| 45 | return false; |
| 46 | } |
| 47 | |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 48 | // Verify that tab IDs appear only once within a session. Intended to prevent |
| 49 | // http://crbug.com/360822. |
| 50 | bool IsValidSessionHeader(const sync_pb::SessionHeader& header) { |
| 51 | std::set<int> session_tab_ids; |
| 52 | for (int i = 0; i < header.window_size(); ++i) { |
| 53 | const sync_pb::SessionWindow& window = header.window(i); |
| 54 | for (int j = 0; j < window.tab_size(); ++j) { |
| 55 | const int tab_id = window.tab(j); |
| 56 | bool success = session_tab_ids.insert(tab_id).second; |
| 57 | if (!success) |
| 58 | return false; |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | return true; |
| 63 | } |
| 64 | |
| 65 | void PopulateSyncedSessionWindowFromSpecifics( |
| 66 | const std::string& session_tag, |
| 67 | const sync_pb::SessionWindow& specifics, |
| 68 | base::Time mtime, |
| 69 | SyncedSessionWindow* synced_session_window, |
| 70 | SyncedSessionTracker* tracker) { |
| 71 | sessions::SessionWindow* session_window = |
| 72 | &synced_session_window->wrapped_window; |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 73 | if (specifics.has_window_id()) { |
| 74 | session_window->window_id = |
| 75 | SessionID::FromSerializedValue(specifics.window_id()); |
| 76 | } |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 77 | if (specifics.has_selected_tab_index()) |
| 78 | session_window->selected_tab_index = specifics.selected_tab_index(); |
| 79 | synced_session_window->window_type = specifics.browser_type(); |
| 80 | if (specifics.has_browser_type()) { |
| 81 | if (specifics.browser_type() == |
| 82 | sync_pb::SessionWindow_BrowserType_TYPE_TABBED) { |
| 83 | session_window->type = sessions::SessionWindow::TYPE_TABBED; |
| 84 | } else { |
| 85 | // Note: custom tabs are treated like popup windows on restore, as you can |
| 86 | // restore a custom tab on a platform that doesn't support them. |
| 87 | session_window->type = sessions::SessionWindow::TYPE_POPUP; |
| 88 | } |
| 89 | } |
| 90 | session_window->timestamp = mtime; |
| 91 | session_window->tabs.clear(); |
| 92 | for (int i = 0; i < specifics.tab_size(); i++) { |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 93 | SessionID tab_id = SessionID::FromSerializedValue(specifics.tab(i)); |
| 94 | tracker->PutTabInWindow(session_tag, session_window->window_id, tab_id); |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 95 | } |
| 96 | } |
| 97 | |
| 98 | void PopulateSyncedSessionFromSpecifics( |
| 99 | const std::string& session_tag, |
| 100 | const sync_pb::SessionHeader& header_specifics, |
| 101 | base::Time mtime, |
| 102 | SyncedSession* synced_session, |
| 103 | SyncedSessionTracker* tracker) { |
| 104 | if (header_specifics.has_client_name()) |
| 105 | synced_session->session_name = header_specifics.client_name(); |
| 106 | if (header_specifics.has_device_type()) { |
| 107 | synced_session->device_type = header_specifics.device_type(); |
| 108 | } |
| 109 | synced_session->modified_time = |
| 110 | std::max(mtime, synced_session->modified_time); |
| 111 | |
| 112 | // Process all the windows and their tab information. |
| 113 | int num_windows = header_specifics.window_size(); |
| 114 | DVLOG(1) << "Populating " << session_tag << " with " << num_windows |
| 115 | << " windows."; |
| 116 | |
| 117 | for (int i = 0; i < num_windows; ++i) { |
| 118 | const sync_pb::SessionWindow& window_s = header_specifics.window(i); |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 119 | SessionID window_id = SessionID::FromSerializedValue(window_s.window_id()); |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 120 | tracker->PutWindowInSession(session_tag, window_id); |
| 121 | PopulateSyncedSessionWindowFromSpecifics( |
| 122 | session_tag, window_s, synced_session->modified_time, |
| 123 | synced_session->windows[window_id].get(), tracker); |
| 124 | } |
| 125 | } |
| 126 | |
zea | f09345c | 2015-10-27 05:29:50 | [diff] [blame] | 127 | } // namespace |
| 128 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 129 | SyncedSessionTracker::TrackedSession::TrackedSession() {} |
| 130 | |
| 131 | SyncedSessionTracker::TrackedSession::~TrackedSession() {} |
| 132 | |
maxbogue | a79d99b7 | 2016-09-15 15:59:16 | [diff] [blame] | 133 | SyncedSessionTracker::SyncedSessionTracker(SyncSessionsClient* sessions_client) |
zea | f09345c | 2015-10-27 05:29:50 | [diff] [blame] | 134 | : sessions_client_(sessions_client) {} |
| 135 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 136 | SyncedSessionTracker::~SyncedSessionTracker() {} |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 137 | |
Mikel Astiz | 556bf09 | 2018-03-06 13:16:33 | [diff] [blame] | 138 | void SyncedSessionTracker::InitLocalSession( |
| 139 | const std::string& local_session_tag, |
| 140 | const std::string& local_session_name, |
| 141 | sync_pb::SyncEnums::DeviceType local_device_type) { |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 142 | DCHECK(local_session_tag_.empty()); |
| 143 | DCHECK(!local_session_tag.empty()); |
[email protected] | 819f753f | 2011-07-15 21:56:02 | [diff] [blame] | 144 | local_session_tag_ = local_session_tag; |
Mikel Astiz | 556bf09 | 2018-03-06 13:16:33 | [diff] [blame] | 145 | |
| 146 | SyncedSession* local_session = GetSession(local_session_tag); |
| 147 | local_session->session_name = local_session_name; |
| 148 | local_session->device_type = local_device_type; |
| 149 | local_session->session_tag = local_session_tag; |
| 150 | } |
| 151 | |
| 152 | const std::string& SyncedSessionTracker::GetLocalSessionTag() const { |
| 153 | return local_session_tag_; |
[email protected] | 819f753f | 2011-07-15 21:56:02 | [diff] [blame] | 154 | } |
| 155 | |
Mikel Astiz | aadda591 | 2018-04-13 11:14:37 | [diff] [blame] | 156 | std::vector<const SyncedSession*> SyncedSessionTracker::LookupAllSessions( |
| 157 | SessionLookup lookup) const { |
| 158 | return LookupSessions(lookup, /*exclude_local_session=*/false); |
| 159 | } |
| 160 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 161 | std::vector<const SyncedSession*> |
| 162 | SyncedSessionTracker::LookupAllForeignSessions(SessionLookup lookup) const { |
Mikel Astiz | aadda591 | 2018-04-13 11:14:37 | [diff] [blame] | 163 | return LookupSessions(lookup, /*exclude_local_session=*/true); |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 164 | } |
| 165 | |
| 166 | bool SyncedSessionTracker::LookupSessionWindows( |
| 167 | const std::string& session_tag, |
skuhne | b7409dcf | 2014-11-14 04:06:55 | [diff] [blame] | 168 | std::vector<const sessions::SessionWindow*>* windows) const { |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 169 | DCHECK(windows); |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 170 | windows->clear(); |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 171 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 172 | const TrackedSession* session = LookupTrackedSession(session_tag); |
| 173 | if (!session) |
| 174 | return false; // We have no record of this session. |
| 175 | |
| 176 | for (const auto& window_pair : session->synced_session.windows) |
zea | 325508e | 2017-03-29 20:11:22 | [diff] [blame] | 177 | windows->push_back(&window_pair.second->wrapped_window); |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 178 | |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 179 | return true; |
| 180 | } |
| 181 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 182 | const sessions::SessionTab* SyncedSessionTracker::LookupSessionTab( |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 183 | const std::string& tag, |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 184 | SessionID tab_id) const { |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 185 | if (!tab_id.is_valid()) |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 186 | return nullptr; |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 187 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 188 | const TrackedSession* session = LookupTrackedSession(tag); |
| 189 | if (!session) |
| 190 | return nullptr; // We have no record of this session. |
| 191 | |
| 192 | auto tab_iter = session->synced_tab_map.find(tab_id); |
| 193 | if (tab_iter == session->synced_tab_map.end()) |
| 194 | return nullptr; // We have no record of this tab. |
| 195 | |
| 196 | return tab_iter->second; |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 197 | } |
| 198 | |
Mikel Astiz | 5e4a71b | 2018-04-12 11:57:30 | [diff] [blame] | 199 | std::set<int> SyncedSessionTracker::LookupTabNodeIds( |
| 200 | const std::string& session_tag) const { |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 201 | const TrackedSession* session = LookupTrackedSession(session_tag); |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 202 | return session ? session->tab_node_pool.GetAllTabNodeIds() : std::set<int>(); |
[email protected] | 98f589d | 2013-08-01 05:14:01 | [diff] [blame] | 203 | } |
| 204 | |
Mikel Astiz | aadda591 | 2018-04-13 11:14:37 | [diff] [blame] | 205 | std::vector<const sessions::SessionTab*> |
| 206 | SyncedSessionTracker::LookupUnmappedTabs(const std::string& session_tag) const { |
| 207 | const TrackedSession* session = LookupTrackedSession(session_tag); |
| 208 | std::vector<const sessions::SessionTab*> unmapped_tabs; |
| 209 | if (session) { |
| 210 | for (const auto& unmapped_tab_entry : session->unmapped_tabs) { |
| 211 | unmapped_tabs.push_back(unmapped_tab_entry.second.get()); |
| 212 | } |
| 213 | } |
| 214 | return unmapped_tabs; |
| 215 | } |
| 216 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 217 | const SyncedSession* SyncedSessionTracker::LookupLocalSession() const { |
Mikel Astiz | 5e4a71b | 2018-04-12 11:57:30 | [diff] [blame] | 218 | return LookupSession(local_session_tag_); |
| 219 | } |
| 220 | |
| 221 | const SyncedSession* SyncedSessionTracker::LookupSession( |
| 222 | const std::string& session_tag) const { |
| 223 | const TrackedSession* session = LookupTrackedSession(session_tag); |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 224 | return session ? &session->synced_session : nullptr; |
[email protected] | 85622cd | 2013-12-18 17:32:27 | [diff] [blame] | 225 | } |
| 226 | |
maxbogue | a79d99b7 | 2016-09-15 15:59:16 | [diff] [blame] | 227 | SyncedSession* SyncedSessionTracker::GetSession( |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 228 | const std::string& session_tag) { |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 229 | return &GetTrackedSession(session_tag)->synced_session; |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 230 | } |
| 231 | |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 232 | bool SyncedSessionTracker::DeleteForeignSession( |
| 233 | const std::string& session_tag) { |
| 234 | DCHECK_NE(local_session_tag_, session_tag); |
skym | 199c7fd | 2016-04-14 19:26:42 | [diff] [blame] | 235 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 236 | auto iter = session_map_.find(session_tag); |
| 237 | if (iter == session_map_.end()) |
| 238 | return false; |
skym | 199c7fd | 2016-04-14 19:26:42 | [diff] [blame] | 239 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 240 | // An implicitly created session that has children tabs but no header node |
| 241 | // will have never had the device_type changed from unset. |
| 242 | const bool header_existed = |
| 243 | iter->second.synced_session.device_type != sync_pb::SyncEnums::TYPE_UNSET; |
| 244 | // SyncedSession's destructor will trigger deletion of windows which will in |
| 245 | // turn trigger the deletion of tabs. This doesn't affect the convenience |
| 246 | // maps. |
| 247 | session_map_.erase(iter); |
skym | 199c7fd | 2016-04-14 19:26:42 | [diff] [blame] | 248 | |
| 249 | return header_existed; |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 250 | } |
| 251 | |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 252 | void SyncedSessionTracker::ResetSessionTracking( |
| 253 | const std::string& session_tag) { |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 254 | TrackedSession* session = GetTrackedSession(session_tag); |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 255 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 256 | for (auto& window_pair : session->synced_session.windows) { |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 257 | // First unmap the tabs in the window. |
zea | 325508e | 2017-03-29 20:11:22 | [diff] [blame] | 258 | for (auto& tab : window_pair.second->wrapped_window.tabs) { |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 259 | SessionID tab_id = tab->tab_id; |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 260 | session->unmapped_tabs[tab_id] = std::move(tab); |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 261 | } |
zea | 325508e | 2017-03-29 20:11:22 | [diff] [blame] | 262 | window_pair.second->wrapped_window.tabs.clear(); |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 263 | |
| 264 | // Then unmap the window itself. |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 265 | session->unmapped_windows[window_pair.first] = |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 266 | std::move(window_pair.second); |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 267 | } |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 268 | session->synced_session.windows.clear(); |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 269 | } |
| 270 | |
skym | 199c7fd | 2016-04-14 19:26:42 | [diff] [blame] | 271 | void SyncedSessionTracker::DeleteForeignTab(const std::string& session_tag, |
| 272 | int tab_node_id) { |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 273 | DCHECK_NE(local_session_tag_, session_tag); |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 274 | TrackedSession* session = LookupTrackedSession(session_tag); |
| 275 | if (session) |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 276 | session->tab_node_pool.DeleteTabNode(tab_node_id); |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 277 | } |
| 278 | |
| 279 | const SyncedSessionTracker::TrackedSession* |
| 280 | SyncedSessionTracker::LookupTrackedSession( |
| 281 | const std::string& session_tag) const { |
jdoerrie | 3feb185 | 2018-10-05 12:16:44 | [diff] [blame] | 282 | auto it = session_map_.find(session_tag); |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 283 | return it == session_map_.end() ? nullptr : &it->second; |
| 284 | } |
| 285 | |
| 286 | SyncedSessionTracker::TrackedSession* |
| 287 | SyncedSessionTracker::LookupTrackedSession(const std::string& session_tag) { |
jdoerrie | 3feb185 | 2018-10-05 12:16:44 | [diff] [blame] | 288 | auto it = session_map_.find(session_tag); |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 289 | return it == session_map_.end() ? nullptr : &it->second; |
| 290 | } |
| 291 | |
| 292 | SyncedSessionTracker::TrackedSession* SyncedSessionTracker::GetTrackedSession( |
| 293 | const std::string& session_tag) { |
| 294 | TrackedSession* session = LookupTrackedSession(session_tag); |
| 295 | if (session) |
| 296 | return session; |
| 297 | |
| 298 | session = &session_map_[session_tag]; |
| 299 | DVLOG(1) << "Creating new session with tag " << session_tag << " at " |
| 300 | << session; |
| 301 | session->synced_session.session_tag = session_tag; |
| 302 | return session; |
skym | 199c7fd | 2016-04-14 19:26:42 | [diff] [blame] | 303 | } |
| 304 | |
Mikel Astiz | aadda591 | 2018-04-13 11:14:37 | [diff] [blame] | 305 | std::vector<const SyncedSession*> SyncedSessionTracker::LookupSessions( |
| 306 | SessionLookup lookup, |
| 307 | bool exclude_local_session) const { |
| 308 | std::vector<const SyncedSession*> sessions; |
| 309 | for (const auto& session_pair : session_map_) { |
| 310 | const SyncedSession& session = session_pair.second.synced_session; |
| 311 | if (lookup == PRESENTABLE && !IsPresentable(sessions_client_, session)) { |
| 312 | continue; |
| 313 | } |
| 314 | if (exclude_local_session && session_pair.first == local_session_tag_) { |
| 315 | continue; |
| 316 | } |
| 317 | sessions.push_back(&session); |
| 318 | } |
| 319 | return sessions; |
| 320 | } |
| 321 | |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 322 | void SyncedSessionTracker::CleanupSessionImpl(const std::string& session_tag) { |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 323 | TrackedSession* session = LookupTrackedSession(session_tag); |
| 324 | if (!session) |
| 325 | return; |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 326 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 327 | for (const auto& window_pair : session->unmapped_windows) |
| 328 | session->synced_window_map.erase(window_pair.first); |
| 329 | session->unmapped_windows.clear(); |
| 330 | |
Mikel Astiz | c8e9872 | 2018-09-05 11:08:29 | [diff] [blame] | 331 | for (const auto& tab_pair : session->unmapped_tabs) { |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 332 | session->synced_tab_map.erase(tab_pair.first); |
Mikel Astiz | c8e9872 | 2018-09-05 11:08:29 | [diff] [blame] | 333 | |
| 334 | if (session_tag == local_session_tag_) |
| 335 | session->tab_node_pool.FreeTab(tab_pair.first); |
| 336 | } |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 337 | session->unmapped_tabs.clear(); |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 338 | } |
| 339 | |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 340 | bool SyncedSessionTracker::IsTabUnmappedForTesting(SessionID tab_id) { |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 341 | const TrackedSession* session = LookupTrackedSession(local_session_tag_); |
| 342 | if (!session) |
| 343 | return false; |
| 344 | |
| 345 | return session->unmapped_tabs.count(tab_id) != 0; |
| 346 | } |
| 347 | |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 348 | void SyncedSessionTracker::PutWindowInSession(const std::string& session_tag, |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 349 | SessionID window_id) { |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 350 | TrackedSession* session = GetTrackedSession(session_tag); |
| 351 | if (session->synced_session.windows.count(window_id) != 0) { |
zea | 92d4a10 | 2017-04-18 06:26:07 | [diff] [blame] | 352 | DVLOG(1) << "Window " << window_id << " already added to session " |
| 353 | << session_tag; |
| 354 | return; |
| 355 | } |
zea | 325508e | 2017-03-29 20:11:22 | [diff] [blame] | 356 | std::unique_ptr<SyncedSessionWindow> window; |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 357 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 358 | auto iter = session->unmapped_windows.find(window_id); |
| 359 | if (iter != session->unmapped_windows.end()) { |
| 360 | DCHECK_EQ(session->synced_window_map[window_id], iter->second.get()); |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 361 | window = std::move(iter->second); |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 362 | session->unmapped_windows.erase(iter); |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 363 | DVLOG(1) << "Putting seen window " << window_id << " at " << window.get() |
zea | c2f678e | 2015-10-28 06:16:10 | [diff] [blame] | 364 | << "in " << (session_tag == local_session_tag_ ? "local session" |
| 365 | : session_tag); |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 366 | } else { |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 367 | // Create the window. |
Sky Malice | 08a04b7 | 2017-08-24 21:43:24 | [diff] [blame] | 368 | window = std::make_unique<SyncedSessionWindow>(); |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 369 | window->wrapped_window.window_id = window_id; |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 370 | session->synced_window_map[window_id] = window.get(); |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 371 | DVLOG(1) << "Putting new window " << window_id << " at " << window.get() |
zea | c2f678e | 2015-10-28 06:16:10 | [diff] [blame] | 372 | << "in " << (session_tag == local_session_tag_ ? "local session" |
| 373 | : session_tag); |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 374 | } |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 375 | DCHECK_EQ(window->wrapped_window.window_id, window_id); |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 376 | DCHECK(GetSession(session_tag)->windows.end() == |
| 377 | GetSession(session_tag)->windows.find(window_id)); |
| 378 | GetSession(session_tag)->windows[window_id] = std::move(window); |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 379 | } |
| 380 | |
| 381 | void SyncedSessionTracker::PutTabInWindow(const std::string& session_tag, |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 382 | SessionID window_id, |
| 383 | SessionID tab_id) { |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 384 | TrackedSession* session = LookupTrackedSession(session_tag); |
| 385 | DCHECK(session); |
| 386 | |
[email protected] | 98f589d | 2013-08-01 05:14:01 | [diff] [blame] | 387 | // We're called here for two reasons. 1) We've received an update to the |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 388 | // SessionWindow information of a SessionHeader node for a session, |
[email protected] | 98f589d | 2013-08-01 05:14:01 | [diff] [blame] | 389 | // and 2) The SessionHeader node for our local session changed. In both cases |
| 390 | // we need to update our tracking state to reflect the change. |
| 391 | // |
| 392 | // Because the SessionHeader nodes are separate from the individual tab nodes |
| 393 | // and we don't store tab_node_ids in the header / SessionWindow specifics, |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 394 | // the tab_node_ids are not always available when processing headers. We know |
| 395 | // that we will eventually process (via GetTab) every single tab node in the |
| 396 | // system, so we permit ourselves to just call GetTab and ignore the result, |
| 397 | // creating a placeholder SessionTab in the process. |
| 398 | sessions::SessionTab* tab_ptr = GetTab(session_tag, tab_id); |
[email protected] | abb35c1 | 2014-08-21 20:13:44 | [diff] [blame] | 399 | |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 400 | // The tab should be unmapped. |
| 401 | std::unique_ptr<sessions::SessionTab> tab; |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 402 | auto it = session->unmapped_tabs.find(tab_id); |
| 403 | if (it != session->unmapped_tabs.end()) { |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 404 | tab = std::move(it->second); |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 405 | session->unmapped_tabs.erase(it); |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 406 | } else { |
| 407 | // The tab has already been mapped, possibly because of the tab node id |
| 408 | // being reused across tabs. Find the existing tab and move it to the right |
| 409 | // window. |
| 410 | for (auto& window_iter_pair : GetSession(session_tag)->windows) { |
| 411 | auto tab_iter = std::find_if( |
zea | 325508e | 2017-03-29 20:11:22 | [diff] [blame] | 412 | window_iter_pair.second->wrapped_window.tabs.begin(), |
| 413 | window_iter_pair.second->wrapped_window.tabs.end(), |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 414 | [&tab_ptr](const std::unique_ptr<sessions::SessionTab>& tab) { |
| 415 | return tab.get() == tab_ptr; |
| 416 | }); |
zea | 325508e | 2017-03-29 20:11:22 | [diff] [blame] | 417 | if (tab_iter != window_iter_pair.second->wrapped_window.tabs.end()) { |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 418 | tab = std::move(*tab_iter); |
zea | 325508e | 2017-03-29 20:11:22 | [diff] [blame] | 419 | window_iter_pair.second->wrapped_window.tabs.erase(tab_iter); |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 420 | |
| 421 | DVLOG(1) << "Moving tab " << tab_id << " from window " |
| 422 | << window_iter_pair.first << " to " << window_id; |
| 423 | break; |
| 424 | } |
| 425 | } |
| 426 | // TODO(zea): remove this once PutTabInWindow isn't crashing anymore. |
| 427 | CHECK(tab) << " Unable to find tab " << tab_id |
| 428 | << " within unmapped tabs or previously mapped windows." |
Sky Malice | 88982246 | 2018-01-03 00:34:04 | [diff] [blame] | 429 | << " https://crbug.com/639009"; |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 430 | } |
[email protected] | abb35c1 | 2014-08-21 20:13:44 | [diff] [blame] | 431 | |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 432 | tab->window_id = window_id; |
zea | c2f678e | 2015-10-28 06:16:10 | [diff] [blame] | 433 | DVLOG(1) << " - tab " << tab_id << " added to window " << window_id; |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 434 | DCHECK(GetSession(session_tag)->windows.find(window_id) != |
| 435 | GetSession(session_tag)->windows.end()); |
zea | 325508e | 2017-03-29 20:11:22 | [diff] [blame] | 436 | GetSession(session_tag) |
| 437 | ->windows[window_id] |
| 438 | ->wrapped_window.tabs.push_back(std::move(tab)); |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 439 | } |
| 440 | |
| 441 | void SyncedSessionTracker::OnTabNodeSeen(const std::string& session_tag, |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 442 | int tab_node_id, |
| 443 | SessionID tab_id) { |
| 444 | // TODO(mastiz): Revisit if the exception for |local_session_tag_| can be |
| 445 | // avoided and treat all sessions equally, which ideally involves merging this |
| 446 | // function with ReassociateLocalTab(). |
| 447 | if (session_tag != local_session_tag_ && |
| 448 | tab_node_id != TabNodePool::kInvalidTabNodeID) { |
| 449 | GetTrackedSession(session_tag) |
| 450 | ->tab_node_pool.ReassociateTabNode(tab_node_id, tab_id); |
Mikel Astiz | 5e4a71b | 2018-04-12 11:57:30 | [diff] [blame] | 451 | } |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 452 | } |
| 453 | |
zea | 159246f2 | 2016-12-07 00:40:34 | [diff] [blame] | 454 | sessions::SessionTab* SyncedSessionTracker::GetTab( |
[email protected] | 98f589d | 2013-08-01 05:14:01 | [diff] [blame] | 455 | const std::string& session_tag, |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 456 | SessionID tab_id) { |
| 457 | CHECK(tab_id.is_valid()) << "https://crbug.com/639009"; |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 458 | |
| 459 | TrackedSession* session = GetTrackedSession(session_tag); |
skym | 199c7fd | 2016-04-14 19:26:42 | [diff] [blame] | 460 | sessions::SessionTab* tab_ptr = nullptr; |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 461 | auto iter = session->synced_tab_map.find(tab_id); |
| 462 | if (iter != session->synced_tab_map.end()) { |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 463 | tab_ptr = iter->second; |
[email protected] | 98f589d | 2013-08-01 05:14:01 | [diff] [blame] | 464 | |
[email protected] | 35d849dc | 2011-10-21 23:49:05 | [diff] [blame] | 465 | if (VLOG_IS_ON(1)) { |
| 466 | std::string title; |
| 467 | if (tab_ptr->navigations.size() > 0) { |
zea | c2f678e | 2015-10-28 06:16:10 | [diff] [blame] | 468 | title = |
thestig | ee1440b | 2016-07-08 01:06:55 | [diff] [blame] | 469 | " (" + base::UTF16ToUTF8(tab_ptr->navigations.back().title()) + ")"; |
[email protected] | 35d849dc | 2011-10-21 23:49:05 | [diff] [blame] | 470 | } |
[email protected] | 060588c | 2011-11-29 21:38:41 | [diff] [blame] | 471 | DVLOG(1) << "Getting " |
zea | c2f678e | 2015-10-28 06:16:10 | [diff] [blame] | 472 | << (session_tag == local_session_tag_ ? "local session" |
| 473 | : session_tag) |
thestig | ee1440b | 2016-07-08 01:06:55 | [diff] [blame] | 474 | << "'s seen tab " << tab_id << " at " << tab_ptr << " " << title; |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 475 | } |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 476 | } else { |
Sky Malice | 5ecd663 | 2018-01-19 18:03:07 | [diff] [blame] | 477 | auto tab = std::make_unique<sessions::SessionTab>(); |
avi | 498cabca | 2016-09-21 19:03:50 | [diff] [blame] | 478 | tab_ptr = tab.get(); |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 479 | tab->tab_id = tab_id; |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 480 | session->synced_tab_map[tab_id] = tab_ptr; |
| 481 | session->unmapped_tabs[tab_id] = std::move(tab); |
[email protected] | 060588c | 2011-11-29 21:38:41 | [diff] [blame] | 482 | DVLOG(1) << "Getting " |
zea | c2f678e | 2015-10-28 06:16:10 | [diff] [blame] | 483 | << (session_tag == local_session_tag_ ? "local session" |
| 484 | : session_tag) |
| 485 | << "'s new tab " << tab_id << " at " << tab_ptr; |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 486 | } |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 487 | DCHECK(tab_ptr); |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 488 | DCHECK_EQ(tab_ptr->tab_id, tab_id); |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 489 | return tab_ptr; |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 490 | } |
| 491 | |
zea | 92d4a10 | 2017-04-18 06:26:07 | [diff] [blame] | 492 | void SyncedSessionTracker::CleanupSession(const std::string& session_tag) { |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 493 | CleanupSessionImpl(session_tag); |
| 494 | } |
| 495 | |
| 496 | void SyncedSessionTracker::CleanupLocalTabs(std::set<int>* deleted_node_ids) { |
| 497 | DCHECK(!local_session_tag_.empty()); |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 498 | TrackedSession* session = GetTrackedSession(local_session_tag_); |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 499 | CleanupSessionImpl(local_session_tag_); |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 500 | session->tab_node_pool.CleanupTabNodes(deleted_node_ids); |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 501 | } |
| 502 | |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 503 | int SyncedSessionTracker::LookupTabNodeFromTabId(const std::string& session_tag, |
| 504 | SessionID tab_id) const { |
| 505 | const TrackedSession* session = LookupTrackedSession(session_tag); |
| 506 | DCHECK(session); |
| 507 | return session->tab_node_pool.GetTabNodeIdFromTabId(tab_id); |
| 508 | } |
| 509 | |
| 510 | SessionID SyncedSessionTracker::LookupTabIdFromTabNodeId( |
| 511 | const std::string& session_tag, |
| 512 | int tab_node_id) const { |
| 513 | const TrackedSession* session = LookupTrackedSession(session_tag); |
| 514 | DCHECK(session); |
| 515 | return session->tab_node_pool.GetTabIdFromTabNodeId(tab_node_id); |
Mikel Astiz | aadda591 | 2018-04-13 11:14:37 | [diff] [blame] | 516 | } |
| 517 | |
Mikel Astiz | cb491c4cb | 2018-05-24 13:08:26 | [diff] [blame] | 518 | int SyncedSessionTracker::AssociateLocalTabWithFreeTabNode(SessionID tab_id) { |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 519 | DCHECK(!local_session_tag_.empty()); |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 520 | TrackedSession* session = GetTrackedSession(local_session_tag_); |
| 521 | |
zea | 92d4a10 | 2017-04-18 06:26:07 | [diff] [blame] | 522 | // Ensure a placeholder SessionTab is in place, if not already. Although we |
| 523 | // don't need a SessionTab to fulfill this request, this forces the creation |
| 524 | // of one if it doesn't already exist. This helps to make sure we're tracking |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 525 | // this |tab_id| if TabNodePool is, and everyone's data structures are kept in |
| 526 | // sync and as consistent as possible. |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 527 | GetTab(local_session_tag_, tab_id); // Ignore result. |
| 528 | |
Mikel Astiz | cb491c4cb | 2018-05-24 13:08:26 | [diff] [blame] | 529 | return session->tab_node_pool.AssociateWithFreeTabNode(tab_id); |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 530 | } |
| 531 | |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 532 | void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id, |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 533 | SessionID new_tab_id) { |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 534 | DCHECK(!local_session_tag_.empty()); |
| 535 | DCHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id); |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 536 | DCHECK(new_tab_id.is_valid()); |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 537 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 538 | TrackedSession* session = LookupTrackedSession(local_session_tag_); |
| 539 | DCHECK(session); |
| 540 | |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 541 | SessionID old_tab_id = |
| 542 | session->tab_node_pool.GetTabIdFromTabNodeId(tab_node_id); |
zea | 783900c | 2017-05-05 00:46:47 | [diff] [blame] | 543 | if (new_tab_id == old_tab_id) { |
| 544 | return; |
| 545 | } |
| 546 | |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 547 | session->tab_node_pool.ReassociateTabNode(tab_node_id, new_tab_id); |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 548 | |
| 549 | sessions::SessionTab* tab_ptr = nullptr; |
| 550 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 551 | auto new_tab_iter = session->synced_tab_map.find(new_tab_id); |
| 552 | auto old_tab_iter = session->synced_tab_map.find(old_tab_id); |
| 553 | if (old_tab_id.is_valid() && old_tab_iter != session->synced_tab_map.end()) { |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 554 | tab_ptr = old_tab_iter->second; |
zea | 783900c | 2017-05-05 00:46:47 | [diff] [blame] | 555 | DCHECK(tab_ptr); |
| 556 | |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 557 | // Remove the tab from the synced tab map under the old id. |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 558 | session->synced_tab_map.erase(old_tab_iter); |
zea | 783900c | 2017-05-05 00:46:47 | [diff] [blame] | 559 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 560 | if (new_tab_iter != session->synced_tab_map.end()) { |
zea | 783900c | 2017-05-05 00:46:47 | [diff] [blame] | 561 | // If both the old and the new tab already exist, delete the new tab |
| 562 | // and use the old tab in its place. |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 563 | auto unmapped_tabs_iter = session->unmapped_tabs.find(new_tab_id); |
| 564 | if (unmapped_tabs_iter != session->unmapped_tabs.end()) { |
| 565 | session->unmapped_tabs.erase(unmapped_tabs_iter); |
zea | 783900c | 2017-05-05 00:46:47 | [diff] [blame] | 566 | } else { |
| 567 | sessions::SessionTab* new_tab_ptr = new_tab_iter->second; |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 568 | for (auto& window_iter_pair : session->synced_session.windows) { |
zea | 783900c | 2017-05-05 00:46:47 | [diff] [blame] | 569 | auto& window_tabs = window_iter_pair.second->wrapped_window.tabs; |
| 570 | auto tab_iter = std::find_if( |
| 571 | window_tabs.begin(), window_tabs.end(), |
| 572 | [&new_tab_ptr](const std::unique_ptr<sessions::SessionTab>& tab) { |
| 573 | return tab.get() == new_tab_ptr; |
| 574 | }); |
| 575 | if (tab_iter != window_tabs.end()) { |
| 576 | window_tabs.erase(tab_iter); |
| 577 | break; |
| 578 | } |
| 579 | } |
| 580 | } |
| 581 | |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 582 | session->synced_tab_map.erase(new_tab_iter); |
zea | 783900c | 2017-05-05 00:46:47 | [diff] [blame] | 583 | } |
| 584 | |
| 585 | // If the old tab is unmapped, update the tab id under which it is |
| 586 | // indexed. |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 587 | auto unmapped_tabs_iter = session->unmapped_tabs.find(old_tab_id); |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 588 | if (old_tab_id.is_valid() && |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 589 | unmapped_tabs_iter != session->unmapped_tabs.end()) { |
zea | 783900c | 2017-05-05 00:46:47 | [diff] [blame] | 590 | std::unique_ptr<sessions::SessionTab> tab = |
| 591 | std::move(unmapped_tabs_iter->second); |
| 592 | DCHECK_EQ(tab_ptr, tab.get()); |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 593 | session->unmapped_tabs.erase(unmapped_tabs_iter); |
| 594 | session->unmapped_tabs[new_tab_id] = std::move(tab); |
zea | 783900c | 2017-05-05 00:46:47 | [diff] [blame] | 595 | } |
| 596 | } |
| 597 | |
| 598 | if (tab_ptr == nullptr) { |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 599 | // It's possible a placeholder is already in place for the new tab. If so, |
| 600 | // reuse it, otherwise create a new one (which will default to unmapped). |
| 601 | tab_ptr = GetTab(local_session_tag_, new_tab_id); |
| 602 | } |
| 603 | |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 604 | // Update the tab id. |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 605 | if (old_tab_id.is_valid()) { |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 606 | DVLOG(1) << "Remapped tab " << old_tab_id << " with node " << tab_node_id |
| 607 | << " to tab " << new_tab_id; |
| 608 | } else { |
| 609 | DVLOG(1) << "Mapped new tab node " << tab_node_id << " to tab " |
| 610 | << new_tab_id; |
| 611 | } |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 612 | tab_ptr->tab_id = new_tab_id; |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 613 | |
| 614 | // Add the tab back into the tab map with the new id. |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 615 | session->synced_tab_map[new_tab_id] = tab_ptr; |
zea | 9b42f431 | 2017-03-01 19:15:44 | [diff] [blame] | 616 | } |
| 617 | |
[email protected] | 13daae6d | 2011-10-04 13:43:12 | [diff] [blame] | 618 | void SyncedSessionTracker::Clear() { |
Mikel Astiz | 6d05289 | 2018-03-29 07:15:55 | [diff] [blame] | 619 | session_map_.clear(); |
[email protected] | 819f753f | 2011-07-15 21:56:02 | [diff] [blame] | 620 | local_session_tag_.clear(); |
[email protected] | d70fb36 | 2011-06-15 15:07:39 | [diff] [blame] | 621 | } |
| 622 | |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 623 | void UpdateTrackerWithSpecifics(const sync_pb::SessionSpecifics& specifics, |
| 624 | base::Time modification_time, |
| 625 | SyncedSessionTracker* tracker) { |
| 626 | std::string session_tag = specifics.session_tag(); |
| 627 | SyncedSession* session = tracker->GetSession(session_tag); |
| 628 | if (specifics.has_header()) { |
| 629 | // Read in the header data for this session. Header data is |
| 630 | // essentially a collection of windows, each of which has an ordered id list |
| 631 | // for their tabs. |
| 632 | |
| 633 | if (!IsValidSessionHeader(specifics.header())) { |
Mikel Astiz | 64d2239 | 2018-05-09 08:33:07 | [diff] [blame] | 634 | DLOG(WARNING) << "Ignoring session node with invalid header " |
| 635 | << "and tag " << session_tag << "."; |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 636 | return; |
| 637 | } |
| 638 | |
| 639 | // Load (or create) the SyncedSession object for this client. |
| 640 | const sync_pb::SessionHeader& header = specifics.header(); |
| 641 | |
| 642 | // Reset the tab/window tracking for this session (must do this before |
| 643 | // we start calling PutWindowInSession and PutTabInWindow so that all |
| 644 | // unused tabs/windows get cleared by the CleanupSession(...) call). |
| 645 | tracker->ResetSessionTracking(session_tag); |
| 646 | |
| 647 | PopulateSyncedSessionFromSpecifics(session_tag, header, modification_time, |
| 648 | session, tracker); |
| 649 | |
| 650 | // Delete any closed windows and unused tabs as necessary. |
| 651 | tracker->CleanupSession(session_tag); |
| 652 | } else if (specifics.has_tab()) { |
| 653 | const sync_pb::SessionTab& tab_s = specifics.tab(); |
Mikel Astiz | e023c57 | 2018-03-28 07:56:56 | [diff] [blame] | 654 | SessionID tab_id = SessionID::FromSerializedValue(tab_s.tab_id()); |
Mikel Astiz | 64d2239 | 2018-05-09 08:33:07 | [diff] [blame] | 655 | if (!tab_id.is_valid()) { |
| 656 | DLOG(WARNING) << "Ignoring session tab with invalid tab ID for session " |
| 657 | << "tag " << session_tag << " and node ID " |
| 658 | << specifics.tab_node_id() << "."; |
| 659 | return; |
| 660 | } |
| 661 | |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 662 | DVLOG(1) << "Populating " << session_tag << "'s tab id " << tab_id |
| 663 | << " from node " << specifics.tab_node_id(); |
| 664 | |
| 665 | // Ensure the tracker is aware of the tab node id. Deleting foreign sessions |
| 666 | // requires deleting all relevant tab nodes, and it's easier to track the |
| 667 | // tab node ids themselves separately from the tab ids. |
| 668 | // |
| 669 | // Note that TabIDs are not stable across restarts of a client. Consider |
| 670 | // this example with two tabs: |
| 671 | // |
| 672 | // http://a.com TabID1 --> NodeIDA |
| 673 | // http://b.com TabID2 --> NodeIDB |
| 674 | // |
| 675 | // After restart, tab ids are reallocated. e.g, one possibility: |
| 676 | // http://a.com TabID2 --> NodeIDA |
| 677 | // http://b.com TabID1 --> NodeIDB |
| 678 | // |
| 679 | // If that happened on a remote client, here we will see an update to |
| 680 | // TabID1 with tab_node_id changing from NodeIDA to NodeIDB, and TabID2 |
| 681 | // with tab_node_id changing from NodeIDB to NodeIDA. |
| 682 | // |
| 683 | // We can also wind up here if we created this tab as an out-of-order |
| 684 | // update to the header node for this session before actually associating |
| 685 | // the tab itself, so the tab node id wasn't available at the time and |
| 686 | // is currently kInvalidTabNodeID. |
| 687 | // |
| 688 | // In both cases, we can safely throw it into the set of node ids. |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 689 | tracker->OnTabNodeSeen(session_tag, specifics.tab_node_id(), tab_id); |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 690 | sessions::SessionTab* tab = tracker->GetTab(session_tag, tab_id); |
| 691 | if (!tab->timestamp.is_null() && tab->timestamp > modification_time) { |
| 692 | DVLOG(1) << "Ignoring " << session_tag << "'s session tab " << tab_id |
| 693 | << " with earlier modification time: " << tab->timestamp |
| 694 | << " vs " << modification_time; |
| 695 | return; |
| 696 | } |
| 697 | |
| 698 | // Update SessionTab based on protobuf. |
Mikel Astiz | 23afb11 | 2018-07-09 18:32:27 | [diff] [blame] | 699 | SetSessionTabFromSyncData(tab_s, modification_time, tab); |
Mikel Astiz | f82416e90 | 2018-02-27 16:11:13 | [diff] [blame] | 700 | |
| 701 | // Update the last modified time. |
| 702 | if (session->modified_time < modification_time) |
| 703 | session->modified_time = modification_time; |
| 704 | } else { |
| 705 | LOG(WARNING) << "Ignoring session node with missing header/tab " |
| 706 | << "fields and tag " << session_tag << "."; |
| 707 | } |
| 708 | } |
| 709 | |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 710 | void SerializeTrackerToSpecifics( |
| 711 | const SyncedSessionTracker& tracker, |
| 712 | const base::RepeatingCallback<void(const std::string& session_name, |
| 713 | sync_pb::SessionSpecifics* specifics)>& |
| 714 | output_cb) { |
| 715 | std::map<std::string, std::set<int>> session_tag_to_node_ids; |
| 716 | for (const SyncedSession* session : |
| 717 | tracker.LookupAllSessions(SyncedSessionTracker::RAW)) { |
| 718 | // Request all tabs. |
| 719 | session_tag_to_node_ids[session->session_tag] = |
| 720 | tracker.LookupTabNodeIds(session->session_tag); |
| 721 | // Request the header too. |
| 722 | session_tag_to_node_ids[session->session_tag].insert( |
| 723 | TabNodePool::kInvalidTabNodeID); |
| 724 | } |
| 725 | SerializePartialTrackerToSpecifics(tracker, session_tag_to_node_ids, |
| 726 | output_cb); |
| 727 | } |
| 728 | |
| 729 | void SerializePartialTrackerToSpecifics( |
| 730 | const SyncedSessionTracker& tracker, |
| 731 | const std::map<std::string, std::set<int>>& session_tag_to_node_ids, |
| 732 | const base::RepeatingCallback<void(const std::string& session_name, |
| 733 | sync_pb::SessionSpecifics* specifics)>& |
| 734 | output_cb) { |
| 735 | for (const auto& session_entry : session_tag_to_node_ids) { |
| 736 | const std::string& session_tag = session_entry.first; |
| 737 | const SyncedSession* session = tracker.LookupSession(session_tag); |
| 738 | if (!session) { |
| 739 | // Unknown session. |
| 740 | continue; |
| 741 | } |
| 742 | |
| 743 | const std::set<int> known_tab_node_ids = |
| 744 | tracker.LookupTabNodeIds(session_tag); |
| 745 | |
| 746 | for (int tab_node_id : session_entry.second) { |
| 747 | // Header entity. |
| 748 | if (tab_node_id == TabNodePool::kInvalidTabNodeID) { |
| 749 | sync_pb::SessionSpecifics header_pb; |
| 750 | header_pb.set_session_tag(session_tag); |
| 751 | session->ToSessionHeaderProto().Swap(header_pb.mutable_header()); |
| 752 | output_cb.Run(session->session_name, &header_pb); |
| 753 | continue; |
| 754 | } |
| 755 | |
| 756 | // Check if |tab_node_id| is known by the tracker. |
| 757 | if (known_tab_node_ids.count(tab_node_id) == 0) { |
| 758 | continue; |
| 759 | } |
| 760 | |
| 761 | // Tab entities. |
| 762 | const SessionID tab_id = |
| 763 | tracker.LookupTabIdFromTabNodeId(session_tag, tab_node_id); |
Mikel Astiz | bdb8846 | 2018-05-09 13:46:00 | [diff] [blame] | 764 | if (!tab_id.is_valid()) { |
| 765 | // This can be the case for tabs that were unmapped because we received |
| 766 | // a new foreign tab with the same tab ID (the last one wins), so we |
| 767 | // don't remember the tab ID for the original |tab_node_id|. Instead of |
| 768 | // returning partially populated SessionSpecifics (without tab ID), we |
| 769 | // simply drop them, because older clients don't handle well such |
| 770 | // invalid specifics. |
| 771 | continue; |
| 772 | } |
| 773 | |
Mikel Astiz | b224349 | 2018-05-04 21:06:20 | [diff] [blame] | 774 | const sessions::SessionTab* tab = |
| 775 | tracker.LookupSessionTab(session_tag, tab_id); |
| 776 | if (tab) { |
| 777 | // Associated/mapped tab node. |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 778 | sync_pb::SessionSpecifics tab_pb; |
| 779 | tab_pb.set_session_tag(session_tag); |
| 780 | tab_pb.set_tab_node_id(tab_node_id); |
Mikel Astiz | 23afb11 | 2018-07-09 18:32:27 | [diff] [blame] | 781 | SessionTabToSyncData(*tab).Swap(tab_pb.mutable_tab()); |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 782 | output_cb.Run(session->session_name, &tab_pb); |
| 783 | continue; |
| 784 | } |
| 785 | |
Mikel Astiz | bdb8846 | 2018-05-09 13:46:00 | [diff] [blame] | 786 | // Create entities for unmapped tabs nodes. |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 787 | sync_pb::SessionSpecifics tab_pb; |
| 788 | tab_pb.set_tab_node_id(tab_node_id); |
| 789 | tab_pb.set_session_tag(session_tag); |
Mikel Astiz | bdb8846 | 2018-05-09 13:46:00 | [diff] [blame] | 790 | tab_pb.mutable_tab()->set_tab_id(tab_id.id()); |
Mikel Astiz | db744b64 | 2018-04-20 10:17:14 | [diff] [blame] | 791 | output_cb.Run(session->session_name, &tab_pb); |
| 792 | } |
| 793 | } |
| 794 | } |
| 795 | |
maxbogue | a79d99b7 | 2016-09-15 15:59:16 | [diff] [blame] | 796 | } // namespace sync_sessions |