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

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

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

Powered by Google App Engine
This is Rietveld 408576698