Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: components/sync_sessions/sessions_sync_manager.cc

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

Powered by Google App Engine
This is Rietveld 408576698