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

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

Issue 2791183003: [Sync] Restore previous session if no tabbed windows present (Closed)
Patch Set: Self review Created 3 years, 8 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" 10 #include "base/format_macros.h"
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 } 103 }
104 } 104 }
105 105
106 // Ensure that the tab id is not invalid. 106 // Ensure that the tab id is not invalid.
107 bool ShouldSyncTabId(SessionID::id_type tab_id) { 107 bool ShouldSyncTabId(SessionID::id_type tab_id) {
108 if (tab_id == kInvalidTabID) 108 if (tab_id == kInvalidTabID)
109 return false; 109 return false;
110 return true; 110 return true;
111 } 111 }
112 112
113 SyncedSession::DeviceType ProtoDeviceTypeToSyncedSessionDeviceType(
114 sync_pb::SyncEnums::DeviceType proto_device_type) {
115 switch (proto_device_type) {
116 case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
117 return SyncedSession::TYPE_WIN;
118 case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
119 return SyncedSession::TYPE_MACOSX;
120 case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
121 return SyncedSession::TYPE_LINUX;
122 case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
123 return SyncedSession::TYPE_CHROMEOS;
124 case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
125 return SyncedSession::TYPE_PHONE;
126 case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
127 return SyncedSession::TYPE_TABLET;
128 case sync_pb::SyncEnums_DeviceType_TYPE_OTHER:
129 // Intentionally fall-through
skym 2017/04/17 20:37:02 Why allow a fall through? Why not have a compile e
Nicolas Zea 2017/04/17 21:24:54 Good call, done.
130 default:
131 return SyncedSession::TYPE_OTHER;
132 }
133 }
134
113 } // namespace 135 } // namespace
114 136
115 // |local_device| is owned by ProfileSyncService, its lifetime exceeds 137 // |local_device| is owned by ProfileSyncService, its lifetime exceeds
116 // lifetime of SessionSyncManager. 138 // lifetime of SessionSyncManager.
117 SessionsSyncManager::SessionsSyncManager( 139 SessionsSyncManager::SessionsSyncManager(
118 sync_sessions::SyncSessionsClient* sessions_client, 140 sync_sessions::SyncSessionsClient* sessions_client,
119 syncer::SyncPrefs* sync_prefs, 141 syncer::SyncPrefs* sync_prefs,
120 LocalDeviceInfoProvider* local_device, 142 LocalDeviceInfoProvider* local_device,
121 LocalSessionEventRouter* router, 143 LocalSessionEventRouter* router,
122 const base::Closure& sessions_updated_callback, 144 const base::Closure& sessions_updated_callback,
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 merge_result.set_error( 244 merge_result.set_error(
223 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); 245 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes));
224 246
225 local_event_router_->StartRoutingTo(this); 247 local_event_router_->StartRoutingTo(this);
226 return merge_result; 248 return merge_result;
227 } 249 }
228 250
229 void SessionsSyncManager::AssociateWindows( 251 void SessionsSyncManager::AssociateWindows(
230 ReloadTabsOption option, 252 ReloadTabsOption option,
231 syncer::SyncChangeList* change_output) { 253 syncer::SyncChangeList* change_output) {
232 const std::string local_tag = current_machine_tag(); 254 // Note that |current_session| is a pointer owned by |session_tracker_|.
233 sync_pb::SessionSpecifics specifics; 255 // |session_tracker_| will continue to update |current_session| under
234 specifics.set_session_tag(local_tag); 256 // the hood, e.g. during ResetSessionTracking(..), so care must be taken
skym 2017/04/17 20:37:02 I don't understand what this means and how you're
Nicolas Zea 2017/04/17 21:24:54 Expanded the comment to clarify. ResetSessionTrack
235 sync_pb::SessionHeader* header_s = specifics.mutable_header(); 257 // accessing it.
236 SyncedSession* current_session = session_tracker_.GetSession(local_tag); 258 SyncedSession* current_session =
237 current_session->modified_time = base::Time::Now(); 259 session_tracker_.GetSession(current_machine_tag());
238 header_s->set_client_name(current_session_name_); 260 current_session->session_name = current_session_name_;
239 header_s->set_device_type(current_device_type_); 261 current_session->device_type =
262 ProtoDeviceTypeToSyncedSessionDeviceType(current_device_type_);
263 current_session->session_tag = current_machine_tag();
240 264
241 session_tracker_.ResetSessionTracking(local_tag);
242 SyncedWindowDelegatesGetter::SyncedWindowDelegateMap windows = 265 SyncedWindowDelegatesGetter::SyncedWindowDelegateMap windows =
243 synced_window_delegates_getter()->GetSyncedWindowDelegates(); 266 synced_window_delegates_getter()->GetSyncedWindowDelegates();
244 267
245 if (option == RELOAD_TABS) { 268 // On Android, it's possible to not have any tabbed windows if this is a cold
246 UMA_HISTOGRAM_COUNTS("Sync.SessionWindows", windows.size()); 269 // start triggered for a custom tab. In that case, the previous session must
270 // be restored, otherwise it will be lost. On the other hand, if there is at
271 // least one tabbed window open, it's safe to overwrite the previous session
272 // entirely. See crbug.com/639009 for more info.
273 bool found_tabbed_window = false;
274 for (auto& window_iter_pair : windows) {
275 if (window_iter_pair.second->IsTypeTabbed())
276 found_tabbed_window = true;
247 } 277 }
248 if (windows.size() == 0) { 278
249 // Assume that the window hasn't loaded. Attempting to associate now would 279 if (found_tabbed_window) {
250 // clobber any old windows, so just return. 280 // Just reset the session tracking. No need to worry about the previous
251 LOG(ERROR) << "No windows present, see crbug.com/639009"; 281 // session; the current tabbed windows are now the source of truth.
252 return; 282 session_tracker_.ResetSessionTracking(current_machine_tag());
283 current_session->modified_time = base::Time::Now();
284 } else {
285 DVLOG(1) << "Found no tabbed windows. Reloading "
286 << current_session->windows.size()
287 << " windows from previous session.";
288
289 // A copy of the specifics must be made because |current_session| will be
290 // updated in place and therefore can't be relied on as the source of truth.
291 sync_pb::SessionHeader header_specifics;
292 header_specifics.CopyFrom(current_session->ToSessionHeaderProto());
293 session_tracker_.ResetSessionTracking(current_machine_tag());
294 PopulateSyncedSessionFromSpecifics(current_machine_tag(), header_specifics,
295 base::Time::Now(), current_session);
296
297 // The tab entities stored in sync have outdated SessionId values. Go
298 // through and update them to the new SessionIds.
299 for (auto& win_iter : current_session->windows) {
300 for (auto& tab : win_iter.second->wrapped_window.tabs) {
301 int sync_id = TabNodePool::kInvalidTabNodeID;
302 if (!session_tracker_.GetTabNodeFromLocalTabId(tab->tab_id.id(),
303 &sync_id) ||
304 sync_id == TabNodePool::kInvalidTabNodeID) {
305 continue;
306 }
307 DVLOG(1) << "Rewriting tab node " << sync_id << " with tab id "
308 << tab->tab_id.id();
309 UpdateTabSpecifics(sync_id, *tab, change_output);
310 }
311 }
253 } 312 }
254 for (auto window_iter_pair : windows) { 313
314 for (auto& window_iter_pair : windows) {
255 const SyncedWindowDelegate* window_delegate = window_iter_pair.second; 315 const SyncedWindowDelegate* window_delegate = window_iter_pair.second;
256 if (option == RELOAD_TABS) { 316 if (option == RELOAD_TABS) {
257 UMA_HISTOGRAM_COUNTS("Sync.SessionTabs", window_delegate->GetTabCount()); 317 UMA_HISTOGRAM_COUNTS("Sync.SessionTabs", window_delegate->GetTabCount());
258 } 318 }
259 319
260 // Make sure the window has tabs and a viewable window. The viewable window 320 // Make sure the window has tabs and a viewable window. The viewable
261 // check is necessary because, for example, when a browser is closed the 321 // window check is necessary because, for example, when a browser is
262 // destructor is not necessarily run immediately. This means its possible 322 // closed the destructor is not necessarily run immediately. This means
263 // for us to get a handle to a browser that is about to be removed. If 323 // its possible for us to get a handle to a browser that is about to be
264 // the tab count is 0 or the window is null, the browser is about to be 324 // removed. If the tab count is 0 or the window is null, the browser is
265 // deleted, so we ignore it. 325 // about to be deleted, so we ignore it.
266 if (window_delegate->ShouldSync() && window_delegate->GetTabCount() && 326 if (window_delegate->ShouldSync() && window_delegate->GetTabCount() &&
267 window_delegate->HasWindow()) { 327 window_delegate->HasWindow()) {
268 sync_pb::SessionWindow window_s; 328 sync_pb::SessionWindow window_s;
269 SessionID::id_type window_id = window_delegate->GetSessionId(); 329 SessionID::id_type window_id = window_delegate->GetSessionId();
270 DVLOG(1) << "Associating window " << window_id << " with " 330 DVLOG(1) << "Associating window " << window_id << " with "
271 << window_delegate->GetTabCount() << " tabs."; 331 << window_delegate->GetTabCount() << " tabs.";
272 window_s.set_window_id(window_id);
273 // Note: We don't bother to set selected tab index anymore. We still
274 // consume it when receiving foreign sessions, as reading it is free, but
275 // it triggers too many sync cycles with too little value to make setting
276 // it worthwhile.
277 if (window_delegate->IsTypeTabbed()) {
278 window_s.set_browser_type(
279 sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
280 } else if (window_delegate->IsTypePopup()) {
281 window_s.set_browser_type(
282 sync_pb::SessionWindow_BrowserType_TYPE_POPUP);
283 } else {
284 // This is a custom tab within an app. These will not be restored on
285 // startup if not present.
286 window_s.set_browser_type(
287 sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB);
288 }
289 332
290 bool found_tabs = false; 333 bool found_tabs = false;
291 for (int j = 0; j < window_delegate->GetTabCount(); ++j) { 334 for (int j = 0; j < window_delegate->GetTabCount(); ++j) {
292 SessionID::id_type tab_id = window_delegate->GetTabIdAt(j); 335 SessionID::id_type tab_id = window_delegate->GetTabIdAt(j);
293 SyncedTabDelegate* synced_tab = window_delegate->GetTabAt(j); 336 SyncedTabDelegate* synced_tab = window_delegate->GetTabAt(j);
294 337
295 // GetTabAt can return a null tab; in that case just skip it. 338 // GetTabAt can return a null tab; in that case just skip it. Similarly,
296 if (!synced_tab) 339 // if for some reason the tab id is invalid, skip it.
340 if (!synced_tab || !ShouldSyncTabId(tab_id))
297 continue; 341 continue;
298 342
299 if (!ShouldSyncTabId(tab_id)) {
300 LOG(ERROR) << "Not syncing invalid tab with id " << tab_id;
301 continue;
302 }
303
304 // Placeholder tabs are those without WebContents, either because they 343 // Placeholder tabs are those without WebContents, either because they
305 // were never loaded into memory or they were evicted from memory 344 // were never loaded into memory or they were evicted from memory
306 // (typically only on Android devices). They only have a tab id, window 345 // (typically only on Android devices). They only have a tab id,
307 // id, and a saved synced id (corresponding to the tab node id). Note 346 // window id, and a saved synced id (corresponding to the tab node
308 // that only placeholders have this sync id, as it's necessary to 347 // id). Note that only placeholders have this sync id, as it's
309 // properly reassociate the tab with the entity that was backing it. 348 // necessary to properly reassociate the tab with the entity that was
349 // backing it.
310 if (synced_tab->IsPlaceholderTab()) { 350 if (synced_tab->IsPlaceholderTab()) {
311 // For tabs without WebContents update the |tab_id| and |window_id|, 351 // For tabs without WebContents update the |tab_id| and |window_id|,
312 // as it could have changed after a session restore. 352 // as it could have changed after a session restore.
313 if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID) { 353 if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID) {
314 AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id, 354 AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id,
315 change_output); 355 change_output);
356 } else {
357 DVLOG(1) << "Placeholder tab " << tab_id << " has no sync id.";
316 } 358 }
317 } else if (RELOAD_TABS == option) { 359 } else if (RELOAD_TABS == option) {
318 AssociateTab(synced_tab, change_output); 360 AssociateTab(synced_tab, change_output);
319 } 361 }
320 362
321 // If the tab was syncable, it would have been added to the tracker 363 // If the tab was syncable, it would have been added to the tracker
322 // either by the above Associate[RestoredPlaceholder]Tab call or by the 364 // either by the above Associate[RestoredPlaceholder]Tab call or by
323 // OnLocalTabModified method invoking AssociateTab directly. Therefore, 365 // the OnLocalTabModified method invoking AssociateTab directly.
324 // we can key whether this window has valid tabs based on the tab's 366 // Therefore, we can key whether this window has valid tabs based on
325 // presence in the tracker. 367 // the tab's presence in the tracker.
326 const sessions::SessionTab* tab = nullptr; 368 const sessions::SessionTab* tab = nullptr;
327 if (session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) { 369 if (session_tracker_.LookupSessionTab(current_machine_tag(), tab_id,
370 &tab)) {
328 found_tabs = true; 371 found_tabs = true;
329 window_s.add_tab(tab_id); 372
373 // Update this window's representation in the synced session tracker.
374 // This is a no-op if called multiple times.
375 session_tracker_.PutWindowInSession(current_machine_tag(), window_id);
376
377 // Put the tab in the window (must happen after the window is added
378 // to the session).
379 session_tracker_.PutTabInWindow(current_machine_tag(), window_id,
380 tab_id);
330 } 381 }
331 } 382 }
332 if (found_tabs) { 383 if (found_tabs) {
333 sync_pb::SessionWindow* header_window = header_s->add_window(); 384 SyncedSessionWindow* synced_session_window =
334 *header_window = window_s; 385 current_session->windows[window_id].get();
335 386 // Note: We don't bother to set selected tab index anymore. We still
skym 2017/04/17 20:37:02 Seems like we should ideally be able to stop commi
Nicolas Zea 2017/04/17 21:24:54 This comment is out of date actually (was copied o
336 // Update this window's representation in the synced session tracker. 387 // consume it when receiving foreign sessions, as reading it is free,
337 session_tracker_.PutWindowInSession(local_tag, window_id); 388 // but it triggers too many sync cycles with too little value to make
338 BuildSyncedSessionFromSpecifics( 389 // setting it worthwhile.
339 local_tag, window_s, current_session->modified_time, 390 if (window_delegate->IsTypeTabbed()) {
340 current_session->windows[window_id].get()); 391 synced_session_window->window_type =
392 sync_pb::SessionWindow_BrowserType_TYPE_TABBED;
393 } else if (window_delegate->IsTypePopup()) {
394 synced_session_window->window_type =
395 sync_pb::SessionWindow_BrowserType_TYPE_POPUP;
396 } else {
397 // This is a custom tab within an app. These will not be restored on
398 // startup if not present.
399 synced_session_window->window_type =
400 sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB;
401 }
341 } 402 }
342 } 403 }
343 } 404 }
344 std::set<int> deleted_tab_node_ids; 405 std::set<int> deleted_tab_node_ids;
345 session_tracker_.CleanupLocalTabs(&deleted_tab_node_ids); 406 session_tracker_.CleanupLocalTabs(&deleted_tab_node_ids);
346 AppendDeletionsForTabNodes(deleted_tab_node_ids, current_machine_tag(), 407 AppendDeletionsForTabNodes(deleted_tab_node_ids, current_machine_tag(),
347 change_output); 408 change_output);
348 409
349 // Always update the header. Sync takes care of dropping this update 410 // Always update the header. Sync takes care of dropping this update
350 // if the entity specifics are identical (i.e windows, client name did 411 // if the entity specifics are identical (i.e windows, client name did
351 // not change). 412 // not change).
352 sync_pb::EntitySpecifics entity; 413 sync_pb::EntitySpecifics entity;
353 entity.mutable_session()->CopyFrom(specifics); 414 entity.mutable_session()->set_session_tag(current_machine_tag());
415 entity.mutable_session()->mutable_header()->CopyFrom(
416 current_session->ToSessionHeaderProto());
354 syncer::SyncData data = syncer::SyncData::CreateLocalData( 417 syncer::SyncData data = syncer::SyncData::CreateLocalData(
355 current_machine_tag(), current_session_name_, entity); 418 current_machine_tag(), current_session_name_, entity);
356 change_output->push_back( 419 change_output->push_back(
357 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); 420 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
358 } 421 }
359 422
360 void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab_delegate, 423 void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab_delegate,
361 syncer::SyncChangeList* change_output) { 424 syncer::SyncChangeList* change_output) {
362 DCHECK(!tab_delegate->IsPlaceholderTab()); 425 DCHECK(!tab_delegate->IsPlaceholderTab());
363 426
364 if (tab_delegate->IsBeingDestroyed()) { 427 if (tab_delegate->IsBeingDestroyed()) {
365 // Do nothing. By not proactively adding the tab to the session, it will be 428 // Do nothing. By not proactively adding the tab to the session, it will be
366 // removed if necessary during subsequent cleanup. 429 // removed if necessary during subsequent cleanup.
367 return; 430 return;
368 } 431 }
369 432
370 if (!tab_delegate->ShouldSync(sessions_client_)) 433 if (!tab_delegate->ShouldSync(sessions_client_))
371 return; 434 return;
372 435
373 SessionID::id_type tab_id = tab_delegate->GetSessionId(); 436 SessionID::id_type tab_id = tab_delegate->GetSessionId();
374 DVLOG(1) << "Syncing tab " << tab_id << " from window " 437 DVLOG(1) << "Syncing tab " << tab_id << " from window "
375 << tab_delegate->GetWindowId(); 438 << tab_delegate->GetWindowId();
376 439
377 int tab_node_id = TabNodePool::kInvalidTabNodeID; 440 int tab_node_id = TabNodePool::kInvalidTabNodeID;
378 bool existing_tab_node = 441 bool existing_tab_node = true;
379 session_tracker_.GetTabNodeFromLocalTabId(tab_id, &tab_node_id); 442 if (session_tracker_.IsLocalTabNodeAssociated(tab_delegate->GetSyncId())) {
380 CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id) << "crbug.com/673618"; 443 tab_node_id = tab_delegate->GetSyncId();
381 tab_delegate->SetSyncId(tab_node_id); 444 session_tracker_.ReassociateLocalTab(tab_node_id, tab_id);
445 } else {
446 existing_tab_node =
447 session_tracker_.GetTabNodeFromLocalTabId(tab_id, &tab_node_id);
448 CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id) << "crbug.com/673618";
449 tab_delegate->SetSyncId(tab_node_id);
450 }
451
382 sessions::SessionTab* session_tab = 452 sessions::SessionTab* session_tab =
383 session_tracker_.GetTab(current_machine_tag(), tab_id); 453 session_tracker_.GetTab(current_machine_tag(), tab_id);
384 454
385 // Get the previously synced url. 455 // Get the previously synced url.
386 int old_index = session_tab->normalized_navigation_index(); 456 int old_index = session_tab->normalized_navigation_index();
387 GURL old_url; 457 GURL old_url;
388 if (session_tab->navigations.size() > static_cast<size_t>(old_index)) 458 if (session_tab->navigations.size() > static_cast<size_t>(old_index))
389 old_url = session_tab->navigations[old_index].virtual_url(); 459 old_url = session_tab->navigations[old_index].virtual_url();
390 460
391 // Update the tracker's session representation. 461 // Update the tracker's session representation.
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 if (!session_tracker_.LookupAllForeignSessions( 696 if (!session_tracker_.LookupAllForeignSessions(
627 sessions, SyncedSessionTracker::PRESENTABLE)) 697 sessions, SyncedSessionTracker::PRESENTABLE))
628 return false; 698 return false;
629 std::sort(sessions->begin(), sessions->end(), SessionsRecencyComparator); 699 std::sort(sessions->begin(), sessions->end(), SessionsRecencyComparator);
630 return true; 700 return true;
631 } 701 }
632 702
633 bool SessionsSyncManager::InitFromSyncModel( 703 bool SessionsSyncManager::InitFromSyncModel(
634 const syncer::SyncDataList& sync_data, 704 const syncer::SyncDataList& sync_data,
635 syncer::SyncChangeList* new_changes) { 705 syncer::SyncChangeList* new_changes) {
706 // Map of all rewritten local ids. Because ids are reset on each restart,
707 // and id generation happens outside of Sync, all ids from a previous local
708 // session must be rewritten in order to be valid.
709 // Key: previous session id. Value: new session id.
710 std::map<SessionID::id_type, SessionID::id_type> session_id_map;
711
636 bool found_current_header = false; 712 bool found_current_header = false;
637 int bad_foreign_hash_count = 0; 713 int bad_foreign_hash_count = 0;
638 for (syncer::SyncDataList::const_iterator it = sync_data.begin(); 714 for (syncer::SyncDataList::const_iterator it = sync_data.begin();
639 it != sync_data.end(); ++it) { 715 it != sync_data.end(); ++it) {
640 const syncer::SyncData& data = *it; 716 const syncer::SyncData& data = *it;
641 DCHECK(data.GetSpecifics().has_session()); 717 DCHECK(data.GetSpecifics().has_session());
642 syncer::SyncDataRemote remote(data); 718 syncer::SyncDataRemote remote(data);
643 const sync_pb::SessionSpecifics& specifics = data.GetSpecifics().session(); 719 const sync_pb::SessionSpecifics& specifics = data.GetSpecifics().session();
644 if (specifics.session_tag().empty() || 720 if (specifics.session_tag().empty() ||
645 (specifics.has_tab() && 721 (specifics.has_tab() &&
(...skipping 16 matching lines...) Expand all
662 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, remote)); 738 syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, remote));
663 } 739 }
664 } else { 740 } else {
665 // This is previously stored local session information. 741 // This is previously stored local session information.
666 if (specifics.has_header() && !found_current_header) { 742 if (specifics.has_header() && !found_current_header) {
667 // This is our previous header node, reuse it. 743 // This is our previous header node, reuse it.
668 found_current_header = true; 744 found_current_header = true;
669 if (specifics.header().has_client_name()) 745 if (specifics.header().has_client_name())
670 current_session_name_ = specifics.header().client_name(); 746 current_session_name_ = specifics.header().client_name();
671 747
672 // TODO(zea): crbug.com/639009 update the tracker with the specifics 748 // The specifics from the SyncData are immutable. Create a mutable copy
673 // from the header node as well. This will be necessary to preserve 749 // to hold the rewritten ids.
674 // the set of open tabs when a custom tab is opened. 750 sync_pb::SessionSpecifics rewritten_specifics(specifics);
751
752 // Go through and generate new tab and window ids as necessary, updating
753 // the specifics in place.
754 for (auto& window :
755 *rewritten_specifics.mutable_header()->mutable_window()) {
756 session_id_map[window.window_id()] = SessionID().id();
757 window.set_window_id(session_id_map[window.window_id()]);
758
759 google::protobuf::RepeatedField<int>* tab_ids = window.mutable_tab();
760 for (int i = 0; i < tab_ids->size(); i++) {
761 auto tab_iter = session_id_map.find(tab_ids->Get(i));
762 if (tab_iter == session_id_map.end()) {
763 session_id_map[tab_ids->Get(i)] = SessionID().id();
skym 2017/04/17 20:37:02 I was really confused by this SessionID call until
Nicolas Zea 2017/04/17 21:24:54 Yeah, I know what you mean. Added a comment to mak
764 }
765 *(tab_ids->Mutable(i)) = session_id_map[tab_ids->Get(i)];
766 // Note: the tab id of the SessionTab will be updated when the tab
767 // node itself is processed.
768 }
769 }
770
771 UpdateTrackerWithSpecifics(rewritten_specifics,
772 remote.GetModifiedTime());
773
774 DVLOG(1) << "Loaded local header and rewrote " << session_id_map.size()
775 << " ids.";
776
675 } else { 777 } else {
676 if (specifics.has_header() || !specifics.has_tab()) { 778 if (specifics.has_header() || !specifics.has_tab()) {
677 LOG(WARNING) << "Found more than one session header node with local " 779 LOG(WARNING) << "Found more than one session header node with local "
678 << "tag."; 780 << "tag.";
679 syncer::SyncChange tombstone(TombstoneTab(specifics)); 781 syncer::SyncChange tombstone(TombstoneTab(specifics));
680 if (tombstone.IsValid()) 782 if (tombstone.IsValid())
681 new_changes->push_back(tombstone); 783 new_changes->push_back(tombstone);
682 } else if (specifics.tab().tab_id() == kInvalidTabID) { 784 } else if (specifics.tab().tab_id() == kInvalidTabID) {
683 LOG(WARNING) << "Found tab node with invalid tab id."; 785 LOG(WARNING) << "Found tab node with invalid tab id.";
684 syncer::SyncChange tombstone(TombstoneTab(specifics)); 786 syncer::SyncChange tombstone(TombstoneTab(specifics));
685 if (tombstone.IsValid()) 787 if (tombstone.IsValid())
686 new_changes->push_back(tombstone); 788 new_changes->push_back(tombstone);
687 } else { 789 } else {
688 // This is a valid old tab node, add it to the tracker and associate 790 // This is a valid old tab node, add it to the tracker and associate
689 // it. 791 // it (using the new tab id).
690 DVLOG(1) << "Associating local tab " << specifics.tab().tab_id() 792 DVLOG(1) << "Associating local tab " << specifics.tab().tab_id()
691 << " with node " << specifics.tab_node_id(); 793 << " with node " << specifics.tab_node_id();
692 session_tracker_.ReassociateLocalTab(specifics.tab_node_id(), 794
693 specifics.tab().tab_id()); 795 // Now file the tab under the new tab id.
694 UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime()); 796 SessionID::id_type new_tab_id = kInvalidTabID;
797 auto iter = session_id_map.find(specifics.tab().tab_id());
798 if (iter != session_id_map.end()) {
799 new_tab_id = iter->second;
800 } else {
801 session_id_map[specifics.tab().tab_id()] = SessionID().id();
802 new_tab_id = session_id_map[specifics.tab().tab_id()];
803 }
804 DVLOG(1) << "Remapping tab " << specifics.tab().tab_id() << " to "
805 << new_tab_id;
806
807 // The specifics from the SyncData are immutable. Create a mutable
808 // copy to hold the rewritten ids.
809 sync_pb::SessionSpecifics rewritten_specifics(specifics);
810 rewritten_specifics.mutable_tab()->set_tab_id(new_tab_id);
811 session_tracker_.ReassociateLocalTab(
812 rewritten_specifics.tab_node_id(), new_tab_id);
813 UpdateTrackerWithSpecifics(rewritten_specifics,
814 remote.GetModifiedTime());
815
816 session_tracker_.ReassociateLocalTab(
817 rewritten_specifics.tab_node_id(), new_tab_id);
695 } 818 }
696 } 819 }
697 } 820 }
698 } 821 }
699 822
700 // Cleanup all foreign sessions, since orphaned tabs may have been added after 823 // Cleanup all foreign sessions, since orphaned tabs may have been added after
701 // the header. 824 // the header.
702 std::vector<const SyncedSession*> sessions; 825 std::vector<const SyncedSession*> sessions;
703 session_tracker_.LookupAllForeignSessions(&sessions, 826 session_tracker_.LookupAllForeignSessions(&sessions,
704 SyncedSessionTracker::RAW); 827 SyncedSessionTracker::RAW);
705 for (const auto* session : sessions) { 828 for (const auto* session : sessions) {
706 session_tracker_.CleanupForeignSession(session->session_tag); 829 session_tracker_.CleanupSession(session->session_tag);
707 } 830 }
708 831
709 UMA_HISTOGRAM_COUNTS_100("Sync.SessionsBadForeignHashOnMergeCount", 832 UMA_HISTOGRAM_COUNTS_100("Sync.SessionsBadForeignHashOnMergeCount",
710 bad_foreign_hash_count); 833 bad_foreign_hash_count);
711 834
712 return found_current_header; 835 return found_current_header;
713 } 836 }
714 837
715 void SessionsSyncManager::UpdateTrackerWithSpecifics( 838 void SessionsSyncManager::UpdateTrackerWithSpecifics(
716 const sync_pb::SessionSpecifics& specifics, 839 const sync_pb::SessionSpecifics& specifics,
717 const base::Time& modification_time) { 840 const base::Time& modification_time) {
718 std::string session_tag = specifics.session_tag(); 841 std::string session_tag = specifics.session_tag();
719 SyncedSession* session = session_tracker_.GetSession(session_tag); 842 SyncedSession* session = session_tracker_.GetSession(session_tag);
720 if (specifics.has_header()) { 843 if (specifics.has_header()) {
721 // Read in the header data for this session. Header data is 844 // Read in the header data for this session. Header data is
722 // essentially a collection of windows, each of which has an ordered id list 845 // essentially a collection of windows, each of which has an ordered id list
723 // for their tabs. 846 // for their tabs.
724 847
725 if (!IsValidSessionHeader(specifics.header())) { 848 if (!IsValidSessionHeader(specifics.header())) {
726 LOG(WARNING) << "Ignoring session node with invalid header " 849 LOG(WARNING) << "Ignoring session node with invalid header "
727 << "and tag " << session_tag << "."; 850 << "and tag " << session_tag << ".";
728 return; 851 return;
729 } 852 }
730 853
731 // Load (or create) the SyncedSession object for this client. 854 // Load (or create) the SyncedSession object for this client.
732 const sync_pb::SessionHeader& header = specifics.header(); 855 const sync_pb::SessionHeader& header = specifics.header();
733 PopulateSessionHeaderFromSpecifics(header, modification_time, session);
734 856
735 // Reset the tab/window tracking for this session (must do this before 857 // Reset the tab/window tracking for this session (must do this before
736 // we start calling PutWindowInSession and PutTabInWindow so that all 858 // we start calling PutWindowInSession and PutTabInWindow so that all
737 // unused tabs/windows get cleared by the CleanupSession(...) call). 859 // unused tabs/windows get cleared by the CleanupSession(...) call).
738 session_tracker_.ResetSessionTracking(session_tag); 860 session_tracker_.ResetSessionTracking(session_tag);
739 861
740 // Process all the windows and their tab information. 862 PopulateSyncedSessionFromSpecifics(session_tag, header, modification_time,
741 int num_windows = header.window_size(); 863 session);
742 DVLOG(1) << "Populating " << session_tag << " with " << num_windows
743 << " windows.";
744 864
745 for (int i = 0; i < num_windows; ++i) {
746 const sync_pb::SessionWindow& window_s = header.window(i);
747 SessionID::id_type window_id = window_s.window_id();
748 session_tracker_.PutWindowInSession(session_tag, window_id);
749 BuildSyncedSessionFromSpecifics(session_tag, window_s, modification_time,
750 session->windows[window_id].get());
751 }
752 // Delete any closed windows and unused tabs as necessary. 865 // Delete any closed windows and unused tabs as necessary.
753 session_tracker_.CleanupForeignSession(session_tag); 866 session_tracker_.CleanupSession(session_tag);
754 } else if (specifics.has_tab()) { 867 } else if (specifics.has_tab()) {
755 const sync_pb::SessionTab& tab_s = specifics.tab(); 868 const sync_pb::SessionTab& tab_s = specifics.tab();
756 SessionID::id_type tab_id = tab_s.tab_id(); 869 SessionID::id_type tab_id = tab_s.tab_id();
757 DVLOG(1) << "Populating " << session_tag << "'s tab id " << tab_id 870 DVLOG(1) << "Populating " << session_tag << "'s tab id " << tab_id
758 << " from node " << specifics.tab_node_id(); 871 << " from node " << specifics.tab_node_id();
759 872
760 // Ensure the tracker is aware of the tab node id. Deleting foreign sessions 873 // Ensure the tracker is aware of the tab node id. Deleting foreign sessions
761 // requires deleting all relevant tab nodes, and it's easier to track the 874 // requires deleting all relevant tab nodes, and it's easier to track the
762 // tab node ids themselves separately from the tab ids. 875 // tab node ids themselves separately from the tab ids.
763 // 876 //
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
815 current_machine_tag_ = persisted_guid; 928 current_machine_tag_ = persisted_guid;
816 DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid; 929 DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid;
817 } else { 930 } else {
818 DCHECK(!cache_guid.empty()); 931 DCHECK(!cache_guid.empty());
819 current_machine_tag_ = BuildMachineTag(cache_guid); 932 current_machine_tag_ = BuildMachineTag(cache_guid);
820 DVLOG(1) << "Creating session sync guid: " << current_machine_tag_; 933 DVLOG(1) << "Creating session sync guid: " << current_machine_tag_;
821 sync_prefs_->SetSyncSessionsGUID(current_machine_tag_); 934 sync_prefs_->SetSyncSessionsGUID(current_machine_tag_);
822 } 935 }
823 } 936 }
824 937
938 void SessionsSyncManager::PopulateSyncedSessionFromSpecifics(
939 const std::string& session_tag,
940 const sync_pb::SessionHeader& header_specifics,
941 base::Time mtime,
942 SyncedSession* synced_session) {
943 if (header_specifics.has_client_name())
944 synced_session->session_name = header_specifics.client_name();
945 if (header_specifics.has_device_type()) {
946 synced_session->device_type = ProtoDeviceTypeToSyncedSessionDeviceType(
947 header_specifics.device_type());
948 }
949 synced_session->modified_time =
950 std::max(mtime, synced_session->modified_time);
951
952 // Process all the windows and their tab information.
953 int num_windows = header_specifics.window_size();
954 DVLOG(1) << "Populating " << session_tag << " with " << num_windows
955 << " windows.";
956
957 for (int i = 0; i < num_windows; ++i) {
958 const sync_pb::SessionWindow& window_s = header_specifics.window(i);
959 SessionID::id_type window_id = window_s.window_id();
960 session_tracker_.PutWindowInSession(session_tag, window_id);
961 PopulateSyncedSessionWindowFromSpecifics(
962 session_tag, window_s, synced_session->modified_time,
963 synced_session->windows[window_id].get());
964 }
965 }
966
825 // static 967 // static
826 void SessionsSyncManager::PopulateSessionHeaderFromSpecifics( 968 void SessionsSyncManager::PopulateSyncedSessionWindowFromSpecifics(
827 const sync_pb::SessionHeader& header_specifics,
828 base::Time mtime,
829 SyncedSession* session_header) {
830 if (header_specifics.has_client_name())
831 session_header->session_name = header_specifics.client_name();
832 if (header_specifics.has_device_type()) {
833 switch (header_specifics.device_type()) {
834 case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
835 session_header->device_type = SyncedSession::TYPE_WIN;
836 break;
837 case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
838 session_header->device_type = SyncedSession::TYPE_MACOSX;
839 break;
840 case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
841 session_header->device_type = SyncedSession::TYPE_LINUX;
842 break;
843 case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
844 session_header->device_type = SyncedSession::TYPE_CHROMEOS;
845 break;
846 case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
847 session_header->device_type = SyncedSession::TYPE_PHONE;
848 break;
849 case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
850 session_header->device_type = SyncedSession::TYPE_TABLET;
851 break;
852 case sync_pb::SyncEnums_DeviceType_TYPE_OTHER:
853 // Intentionally fall-through
854 default:
855 session_header->device_type = SyncedSession::TYPE_OTHER;
856 break;
857 }
858 }
859 session_header->modified_time =
860 std::max(mtime, session_header->modified_time);
861 }
862
863 // static
864 void SessionsSyncManager::BuildSyncedSessionFromSpecifics(
865 const std::string& session_tag, 969 const std::string& session_tag,
866 const sync_pb::SessionWindow& specifics, 970 const sync_pb::SessionWindow& specifics,
867 base::Time mtime, 971 base::Time mtime,
868 SyncedSessionWindow* synced_session_window) { 972 SyncedSessionWindow* synced_session_window) {
869 sessions::SessionWindow* session_window = 973 sessions::SessionWindow* session_window =
870 &synced_session_window->wrapped_window; 974 &synced_session_window->wrapped_window;
871 if (specifics.has_window_id()) 975 if (specifics.has_window_id())
872 session_window->window_id.set_id(specifics.window_id()); 976 session_window->window_id.set_id(specifics.window_id());
873 if (specifics.has_selected_tab_index()) 977 if (specifics.has_selected_tab_index())
874 session_window->selected_tab_index = specifics.selected_tab_index(); 978 session_window->selected_tab_index = specifics.selected_tab_index();
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
1010 1114
1011 // Update tracker with the new association (and inform it of the tab node 1115 // Update tracker with the new association (and inform it of the tab node
1012 // in the process). 1116 // in the process).
1013 session_tracker_.ReassociateLocalTab(tab_delegate.GetSyncId(), new_tab_id); 1117 session_tracker_.ReassociateLocalTab(tab_delegate.GetSyncId(), new_tab_id);
1014 1118
1015 // Update the window id on the SessionTab itself. 1119 // Update the window id on the SessionTab itself.
1016 sessions::SessionTab* local_tab = 1120 sessions::SessionTab* local_tab =
1017 session_tracker_.GetTab(current_machine_tag(), new_tab_id); 1121 session_tracker_.GetTab(current_machine_tag(), new_tab_id);
1018 local_tab->window_id.set_id(new_window_id); 1122 local_tab->window_id.set_id(new_window_id);
1019 1123
1124 UpdateTabSpecifics(tab_delegate.GetSyncId(), *local_tab, change_output);
1125 }
1126
1127 void SessionsSyncManager::UpdateTabSpecifics(
1128 int sync_id,
1129 const sessions::SessionTab& tab,
1130 syncer::SyncChangeList* change_output) {
1020 // Rewrite the specifics based on the reassociated SessionTab to preserve 1131 // Rewrite the specifics based on the reassociated SessionTab to preserve
1021 // the new tab and window ids. 1132 // the new tab and window ids.
1022 sync_pb::EntitySpecifics entity; 1133 sync_pb::EntitySpecifics entity;
1023 entity.mutable_session()->CopyFrom(SessionTabToSpecifics( 1134 entity.mutable_session()->CopyFrom(
1024 *local_tab, current_machine_tag(), tab_delegate.GetSyncId())); 1135 SessionTabToSpecifics(tab, current_machine_tag(), sync_id));
1025 syncer::SyncData data = syncer::SyncData::CreateLocalData( 1136 syncer::SyncData data = syncer::SyncData::CreateLocalData(
1026 TabNodeIdToTag(current_machine_tag(), tab_delegate.GetSyncId()), 1137 TabNodeIdToTag(current_machine_tag(), sync_id), current_session_name_,
1027 current_session_name_, entity); 1138 entity);
1028 change_output->push_back( 1139 change_output->push_back(
1029 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); 1140 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
1030 } 1141 }
1031 1142
1032 // static 1143 // static
1033 void SessionsSyncManager::SetSessionTabFromDelegate( 1144 void SessionsSyncManager::SetSessionTabFromDelegate(
1034 const SyncedTabDelegate& tab_delegate, 1145 const SyncedTabDelegate& tab_delegate,
1035 base::Time mtime, 1146 base::Time mtime,
1036 sessions::SessionTab* session_tab) { 1147 sessions::SessionTab* session_tab) {
1037 DCHECK(session_tab); 1148 DCHECK(session_tab);
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
1126 } 1237 }
1127 1238
1128 // static 1239 // static
1129 std::string SessionsSyncManager::TagHashFromSpecifics( 1240 std::string SessionsSyncManager::TagHashFromSpecifics(
1130 const sync_pb::SessionSpecifics& specifics) { 1241 const sync_pb::SessionSpecifics& specifics) {
1131 return syncer::GenerateSyncableHash(syncer::SESSIONS, 1242 return syncer::GenerateSyncableHash(syncer::SESSIONS,
1132 TagFromSpecifics(specifics)); 1243 TagFromSpecifics(specifics));
1133 } 1244 }
1134 1245
1135 }; // namespace sync_sessions 1246 }; // namespace sync_sessions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698