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

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

Powered by Google App Engine
This is Rietveld 408576698