OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |