OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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 "chrome/browser/sync/glue/session_model_associator.h" | 5 #include "chrome/browser/sync/glue/session_model_associator.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <set> | 8 #include <set> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 sync_pb::SessionHeader* header_s = specifics.mutable_header(); | 173 sync_pb::SessionHeader* header_s = specifics.mutable_header(); |
174 SyncedSession* current_session = | 174 SyncedSession* current_session = |
175 synced_session_tracker_.GetSession(local_tag); | 175 synced_session_tracker_.GetSession(local_tag); |
176 current_session->modified_time = base::Time::Now(); | 176 current_session->modified_time = base::Time::Now(); |
177 header_s->set_client_name(current_session_name_); | 177 header_s->set_client_name(current_session_name_); |
178 header_s->set_device_type(DeviceInfo::GetLocalDeviceType()); | 178 header_s->set_device_type(DeviceInfo::GetLocalDeviceType()); |
179 | 179 |
180 synced_session_tracker_.ResetSessionTracking(local_tag); | 180 synced_session_tracker_.ResetSessionTracking(local_tag); |
181 std::set<SyncedWindowDelegate*> windows = | 181 std::set<SyncedWindowDelegate*> windows = |
182 SyncedWindowDelegate::GetSyncedWindowDelegates(); | 182 SyncedWindowDelegate::GetSyncedWindowDelegates(); |
183 std::set<int64> used_sync_ids; | |
183 for (std::set<SyncedWindowDelegate*>::const_iterator i = | 184 for (std::set<SyncedWindowDelegate*>::const_iterator i = |
184 windows.begin(); i != windows.end(); ++i) { | 185 windows.begin(); i != windows.end(); ++i) { |
185 // Make sure the window has tabs and a viewable window. The viewable window | 186 // Make sure the window has tabs and a viewable window. The viewable window |
186 // check is necessary because, for example, when a browser is closed the | 187 // check is necessary because, for example, when a browser is closed the |
187 // destructor is not necessarily run immediately. This means its possible | 188 // destructor is not necessarily run immediately. This means its possible |
188 // for us to get a handle to a browser that is about to be removed. If | 189 // for us to get a handle to a browser that is about to be removed. If |
189 // the tab count is 0 or the window is NULL, the browser is about to be | 190 // the tab count is 0 or the window is NULL, the browser is about to be |
190 // deleted, so we ignore it. | 191 // deleted, so we ignore it. |
191 if (ShouldSyncWindow(*i) && (*i)->GetTabCount() && (*i)->HasWindow()) { | 192 if (ShouldSyncWindow(*i) && (*i)->GetTabCount() && (*i)->HasWindow()) { |
192 sync_pb::SessionWindow window_s; | 193 sync_pb::SessionWindow window_s; |
(...skipping 10 matching lines...) Expand all Loading... | |
203 sync_pb::SessionWindow_BrowserType_TYPE_TABBED); | 204 sync_pb::SessionWindow_BrowserType_TYPE_TABBED); |
204 } else { | 205 } else { |
205 window_s.set_browser_type( | 206 window_s.set_browser_type( |
206 sync_pb::SessionWindow_BrowserType_TYPE_POPUP); | 207 sync_pb::SessionWindow_BrowserType_TYPE_POPUP); |
207 } | 208 } |
208 | 209 |
209 // Store the order of tabs. | 210 // Store the order of tabs. |
210 bool found_tabs = false; | 211 bool found_tabs = false; |
211 for (int j = 0; j < (*i)->GetTabCount(); ++j) { | 212 for (int j = 0; j < (*i)->GetTabCount(); ++j) { |
212 SessionID::id_type tab_id = (*i)->GetTabIdAt(j); | 213 SessionID::id_type tab_id = (*i)->GetTabIdAt(j); |
214 SyncedTabDelegate* synced_tab = (*i)->GetTabAt(j); | |
215 | |
216 // GetTabAt can return a null tab, in case tab is null just skip it. | |
Nicolas Zea
2013/06/19 21:35:33
"tab; in that case just skip it."
shashi
2013/06/20 00:49:32
Done.
| |
217 if (!synced_tab) | |
218 continue; | |
219 | |
220 if (!synced_tab->HasWebContents()) { | |
221 // For tabs without webcontents update the tab_id, tab_id could have | |
Nicolas Zea
2013/06/19 21:35:33
"For tabs without WebContents, update the |tab_id|
shashi
2013/06/20 00:49:32
Done.
| |
222 // changed after a session restore. | |
223 if (synced_tab->GetSyncId() > 0 && | |
Nicolas Zea
2013/06/19 21:35:33
!= syncer::kInvalidId
Maybe worth checking whether
shashi
2013/06/20 00:49:32
I cannot check != syncer::kInvalidId, since TabCon
| |
224 UpdateTabIdIfNecessary(synced_tab->GetSyncId(), tab_id)) { | |
Nicolas Zea
2013/06/19 21:35:33
why is this part of the condition? Whether the tab
shashi
2013/06/20 00:49:32
Done, removed the condition. I was guarding agains
| |
225 found_tabs = true; | |
226 used_sync_ids.insert(synced_tab->GetSyncId()); | |
227 window_s.add_tab(tab_id); | |
228 } | |
229 continue; | |
230 } | |
213 | 231 |
214 if (reload_tabs) { | 232 if (reload_tabs) { |
215 SyncedTabDelegate* tab = (*i)->GetTabAt(j); | |
216 // It's possible for GetTabAt to return a tab which has no web | 233 // It's possible for GetTabAt to return a tab which has no web |
217 // contents. We can assume this means the tab already existed but | 234 // contents. We can assume this means the tab already existed but |
218 // hasn't changed, so no need to reassociate. | 235 // hasn't changed, so no need to reassociate. |
219 if (tab && tab->HasWebContents() && !AssociateTab(*tab, error)) { | 236 if (synced_tab->HasWebContents() && |
237 !AssociateTab(synced_tab, error)) { | |
220 // Association failed. Either we need to re-associate, or this is an | 238 // Association failed. Either we need to re-associate, or this is an |
221 // unrecoverable error. | 239 // unrecoverable error. |
222 return false; | 240 return false; |
223 } | 241 } |
224 } | 242 } |
225 | 243 |
226 // If the tab is valid, it would have been added to the tracker either | 244 // If the tab is valid, it would have been added to the tracker either |
227 // by the above AssociateTab call (at association time), or by the | 245 // by the above AssociateTab call (at association time), or by the |
228 // change processor calling AssociateTab for all modified tabs. | 246 // change processor calling AssociateTab for all modified tabs. |
229 // Therefore, we can key whether this window has valid tabs based on | 247 // Therefore, we can key whether this window has valid tabs based on |
230 // the tab's presence in the tracker. | 248 // the tab's presence in the tracker. |
231 const SessionTab* tab = NULL; | 249 const SessionTab* tab = NULL; |
232 if (synced_session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) { | 250 if (synced_session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) { |
233 found_tabs = true; | 251 found_tabs = true; |
252 used_sync_ids.insert(synced_tab->GetSyncId()); | |
234 window_s.add_tab(tab_id); | 253 window_s.add_tab(tab_id); |
235 } | 254 } |
236 } | 255 } |
237 // Only add a window if it contains valid tabs. | 256 // Only add a window if it contains valid tabs. |
238 if (found_tabs) { | 257 if (found_tabs) { |
239 sync_pb::SessionWindow* header_window = header_s->add_window(); | 258 sync_pb::SessionWindow* header_window = header_s->add_window(); |
240 *header_window = window_s; | 259 *header_window = window_s; |
241 | 260 |
242 // Update this window's representation in the synced session tracker. | 261 // Update this window's representation in the synced session tracker. |
243 synced_session_tracker_.PutWindowInSession(local_tag, window_id); | 262 synced_session_tracker_.PutWindowInSession(local_tag, window_id); |
244 PopulateSessionWindowFromSpecifics( | 263 PopulateSessionWindowFromSpecifics( |
245 local_tag, | 264 local_tag, |
246 window_s, | 265 window_s, |
247 base::Time::Now(), | 266 base::Time::Now(), |
248 current_session->windows[window_id], | 267 current_session->windows[window_id], |
249 &synced_session_tracker_); | 268 &synced_session_tracker_); |
250 } | 269 } |
251 } | 270 } |
252 } | 271 } |
272 | |
273 // Free old sync nodes. | |
274 tab_pool_.FreeUnusedTabNodes(used_sync_ids); | |
253 // Free memory for closed windows and tabs. | 275 // Free memory for closed windows and tabs. |
254 synced_session_tracker_.CleanupSession(local_tag); | 276 synced_session_tracker_.CleanupSession(local_tag); |
255 | 277 |
256 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); | 278 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); |
257 syncer::WriteNode header_node(&trans); | 279 syncer::WriteNode header_node(&trans); |
258 if (header_node.InitByIdLookup(local_session_syncid_) != | 280 if (header_node.InitByIdLookup(local_session_syncid_) != |
259 syncer::BaseNode::INIT_OK) { | 281 syncer::BaseNode::INIT_OK) { |
260 if (error) { | 282 if (error) { |
261 *error = error_handler_->CreateAndUploadError( | 283 *error = error_handler_->CreateAndUploadError( |
262 FROM_HERE, | 284 FROM_HERE, |
(...skipping 15 matching lines...) Expand all Loading... | |
278 return window->IsTypeTabbed() || window->IsTypePopup(); | 300 return window->IsTypeTabbed() || window->IsTypePopup(); |
279 } | 301 } |
280 | 302 |
281 bool SessionModelAssociator::AssociateTabs( | 303 bool SessionModelAssociator::AssociateTabs( |
282 const std::vector<SyncedTabDelegate*>& tabs, | 304 const std::vector<SyncedTabDelegate*>& tabs, |
283 syncer::SyncError* error) { | 305 syncer::SyncError* error) { |
284 DCHECK(CalledOnValidThread()); | 306 DCHECK(CalledOnValidThread()); |
285 for (std::vector<SyncedTabDelegate*>::const_iterator i = tabs.begin(); | 307 for (std::vector<SyncedTabDelegate*>::const_iterator i = tabs.begin(); |
286 i != tabs.end(); | 308 i != tabs.end(); |
287 ++i) { | 309 ++i) { |
288 if (!AssociateTab(**i, error)) | 310 if (!AssociateTab(*i, error)) |
289 return false; | 311 return false; |
290 } | 312 } |
291 if (waiting_for_change_) QuitLoopForSubtleTesting(); | 313 if (waiting_for_change_) QuitLoopForSubtleTesting(); |
292 return true; | 314 return true; |
293 } | 315 } |
294 | 316 |
295 bool SessionModelAssociator::AssociateTab(const SyncedTabDelegate& tab, | 317 bool SessionModelAssociator::AssociateTab(SyncedTabDelegate* tab, |
296 syncer::SyncError* error) { | 318 syncer::SyncError* error) { |
297 DCHECK(CalledOnValidThread()); | 319 DCHECK(CalledOnValidThread()); |
320 CHECK(tab); | |
Nicolas Zea
2013/06/19 21:35:33
nit: I don't think this Check is necessary. We'd s
shashi
2013/06/20 00:49:32
Done. Sometimes though, the stack trace of a crash
| |
321 DCHECK(tab->HasWebContents()); | |
298 int64 sync_id; | 322 int64 sync_id; |
299 SessionID::id_type tab_id = tab.GetSessionId(); | 323 SessionID::id_type tab_id = tab->GetSessionId(); |
300 if (tab.IsBeingDestroyed()) { | 324 if (tab->IsBeingDestroyed()) { |
301 // This tab is closing. | 325 // This tab is closing. |
302 TabLinksMap::iterator tab_iter = tab_map_.find(tab_id); | 326 TabLinksMap::iterator tab_iter = tab_map_.find(tab_id); |
303 if (tab_iter == tab_map_.end()) { | 327 if (tab_iter == tab_map_.end()) { |
304 // We aren't tracking this tab (for example, sync setting page). | 328 // We aren't tracking this tab (for example, sync setting page). |
305 return true; | 329 return true; |
306 } | 330 } |
307 tab_pool_.FreeTabNode(tab_iter->second->sync_id()); | 331 tab_pool_.FreeTabNode(tab_iter->second->sync_id()); |
308 tab_map_.erase(tab_iter); | 332 tab_map_.erase(tab_iter); |
309 return true; | 333 return true; |
310 } | 334 } |
311 | 335 |
312 if (!ShouldSyncTab(tab)) | 336 if (!ShouldSyncTab(*tab)) |
313 return true; | 337 return true; |
314 | 338 |
315 TabLinksMap::iterator tab_map_iter = tab_map_.find(tab_id); | 339 TabLinksMap::iterator tab_map_iter = tab_map_.find(tab_id); |
316 TabLink* tab_link = NULL; | 340 TabLink* tab_link = NULL; |
317 if (tab_map_iter == tab_map_.end()) { | 341 if (tab_map_iter == tab_map_.end()) { |
318 // This is a new tab, get a sync node for it. | 342 sync_id = tab->GetSyncId(); |
319 sync_id = tab_pool_.GetFreeTabNode(); | 343 // if there is an old sync node for the tab, reuse it. |
320 if (sync_id == syncer::kInvalidId) { | 344 if (!tab_pool_.ReassociateTabNode(sync_id, tab_id)) { |
321 if (error) { | 345 // This is a new tab, get a sync node for it. |
322 *error = error_handler_->CreateAndUploadError( | 346 sync_id = tab_pool_.GetFreeTabNode(); |
323 FROM_HERE, | 347 if (sync_id == syncer::kInvalidId) { |
324 "Received invalid tab node from tab pool.", | 348 if (error) { |
325 model_type()); | 349 *error = error_handler_->CreateAndUploadError( |
350 FROM_HERE, | |
351 "Received invalid tab node from tab pool.", | |
352 model_type()); | |
353 } | |
354 return false; | |
326 } | 355 } |
327 return false; | 356 tab_pool_.AssociateTabNode(sync_id, tab_id); |
328 } | 357 } |
329 tab_link = new TabLink(sync_id, &tab); | 358 tab_link = new TabLink(sync_id, tab); |
330 tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link); | 359 tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link); |
360 tab->SetSyncId(sync_id); | |
Nicolas Zea
2013/06/19 21:35:33
move this into the if block? It's redundant for su
shashi
2013/06/20 00:49:32
Done. You are right, it is redundant for successfu
| |
331 } else { | 361 } else { |
332 // This tab is already associated with a sync node, reuse it. | 362 // This tab is already associated with a sync node, reuse it. |
333 // Note: on some platforms the tab object may have changed, so we ensure | 363 // Note: on some platforms the tab object may have changed, so we ensure |
334 // the tab link is up to date. | 364 // the tab link is up to date. |
335 tab_link = tab_map_iter->second.get(); | 365 tab_link = tab_map_iter->second.get(); |
336 tab_map_iter->second->set_tab(&tab); | 366 tab_map_iter->second->set_tab(tab); |
337 } | 367 } |
338 DCHECK(tab_link); | 368 DCHECK(tab_link); |
339 DCHECK_NE(tab_link->sync_id(), syncer::kInvalidId); | 369 DCHECK_NE(tab_link->sync_id(), syncer::kInvalidId); |
340 | 370 |
341 DVLOG(1) << "Reloading tab " << tab_id << " from window " | 371 DVLOG(1) << "Reloading tab " << tab_id << " from window " |
342 << tab.GetWindowId(); | 372 << tab->GetWindowId(); |
343 return WriteTabContentsToSyncModel(tab_link, error); | 373 return WriteTabContentsToSyncModel(tab_link, error); |
344 } | 374 } |
345 | 375 |
346 // static | 376 // static |
347 GURL SessionModelAssociator::GetCurrentVirtualURL( | 377 GURL SessionModelAssociator::GetCurrentVirtualURL( |
348 const SyncedTabDelegate& tab_delegate) { | 378 const SyncedTabDelegate& tab_delegate) { |
349 const int current_index = tab_delegate.GetCurrentEntryIndex(); | 379 const int current_index = tab_delegate.GetCurrentEntryIndex(); |
350 const int pending_index = tab_delegate.GetPendingEntryIndex(); | 380 const int pending_index = tab_delegate.GetPendingEntryIndex(); |
351 const NavigationEntry* current_entry = | 381 const NavigationEntry* current_entry = |
352 (current_index == pending_index) ? | 382 (current_index == pending_index) ? |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
724 } else { | 754 } else { |
725 // This is previously stored local session information. | 755 // This is previously stored local session information. |
726 if (specifics.has_header() && | 756 if (specifics.has_header() && |
727 local_session_syncid_ == syncer::kInvalidId) { | 757 local_session_syncid_ == syncer::kInvalidId) { |
728 // This is our previous header node, reuse it. | 758 // This is our previous header node, reuse it. |
729 local_session_syncid_ = id; | 759 local_session_syncid_ = id; |
730 if (specifics.header().has_client_name()) { | 760 if (specifics.header().has_client_name()) { |
731 current_session_name_ = specifics.header().client_name(); | 761 current_session_name_ = specifics.header().client_name(); |
732 } | 762 } |
733 } else { | 763 } else { |
734 if (specifics.has_header()) { | 764 if (specifics.has_header() || !specifics.has_tab() || |
735 LOG(WARNING) << "Found more than one session header node with local " | 765 !specifics.has_tab_node_id() || !specifics.tab().has_tab_id()) { |
736 << " tag."; | 766 LOG(WARNING) << "Found invalid session node, deleting."; |
737 } else if (!specifics.has_tab()) { | 767 sync_node.Tombstone(); |
738 LOG(WARNING) << "Found local node with no header or tag field."; | 768 } else { |
769 // This is a valid old tab node, add it to the pool so it can be | |
770 // reused for reassociation. | |
771 SessionID tab_id; | |
772 tab_id.set_id(specifics.tab().tab_id()); | |
773 tab_pool_.AddTabNode(id, tab_id, specifics.tab_node_id()); | |
739 } | 774 } |
740 | |
741 // TODO(zea): fix this once we add support for reassociating | |
742 // pre-existing tabs with pre-existing tab nodes. We'll need to load | |
743 // the tab_node_id and ensure the tab_pool_ keeps track of them. | |
744 sync_node.Tombstone(); | |
745 } | 775 } |
746 } | 776 } |
747 id = next_id; | 777 id = next_id; |
748 } | 778 } |
749 | 779 |
750 // After updating from sync model all tabid's should be free. | |
751 DCHECK(tab_pool_.full()); | |
752 return true; | 780 return true; |
753 } | 781 } |
754 | 782 |
755 void SessionModelAssociator::AssociateForeignSpecifics( | 783 void SessionModelAssociator::AssociateForeignSpecifics( |
756 const sync_pb::SessionSpecifics& specifics, | 784 const sync_pb::SessionSpecifics& specifics, |
757 const base::Time& modification_time) { | 785 const base::Time& modification_time) { |
758 DCHECK(CalledOnValidThread()); | 786 DCHECK(CalledOnValidThread()); |
759 std::string foreign_session_tag = specifics.session_tag(); | 787 std::string foreign_session_tag = specifics.session_tag(); |
760 if (foreign_session_tag == GetCurrentMachineTag() && !setup_for_test_) | 788 if (foreign_session_tag == GetCurrentMachineTag() && !setup_for_test_) |
761 return; | 789 return; |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1144 } | 1172 } |
1145 | 1173 |
1146 bool SessionModelAssociator::CryptoReadyIfNecessary() { | 1174 bool SessionModelAssociator::CryptoReadyIfNecessary() { |
1147 // We only access the cryptographer while holding a transaction. | 1175 // We only access the cryptographer while holding a transaction. |
1148 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); | 1176 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); |
1149 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes(); | 1177 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes(); |
1150 return !encrypted_types.Has(SESSIONS) || | 1178 return !encrypted_types.Has(SESSIONS) || |
1151 sync_service_->IsCryptographerReady(&trans); | 1179 sync_service_->IsCryptographerReady(&trans); |
1152 } | 1180 } |
1153 | 1181 |
1182 bool SessionModelAssociator::UpdateTabIdIfNecessary( | |
1183 int64 sync_id, | |
1184 SessionID::id_type new_tab_id) { | |
1185 DCHECK_GT(sync_id, 0); | |
1186 SessionID::id_type old_tab_id = tab_pool_.TabIDForSyncID(sync_id); | |
1187 if (old_tab_id != TabNodePool::kInvalidTabID && old_tab_id == new_tab_id) { | |
Nicolas Zea
2013/06/19 21:35:33
Why does it matter whether the tab id changed? Sho
shashi
2013/06/20 00:49:32
Done, in fact removed the return value.
On 2013/06
| |
1188 return true; | |
1189 } | |
1190 | |
1191 // Rewrite tab id if required. | |
1192 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); | |
1193 syncer::WriteNode tab_node(&trans); | |
1194 if (tab_node.InitByIdLookup(sync_id) == syncer::BaseNode::INIT_OK) { | |
1195 sync_pb::SessionSpecifics session_specifics = | |
1196 tab_node.GetSessionSpecifics(); | |
1197 DCHECK(session_specifics.has_tab()); | |
1198 if (session_specifics.has_tab()) { | |
1199 sync_pb::SessionTab* tab_s = session_specifics.mutable_tab(); | |
1200 tab_s->set_tab_id(new_tab_id); | |
1201 tab_node.SetSessionSpecifics(session_specifics); | |
1202 // Update tab node pool with the new association. | |
1203 tab_pool_.ReassociateTabNode(sync_id, new_tab_id); | |
1204 return true; | |
1205 } | |
1206 } | |
1207 return false; | |
1208 } | |
1209 | |
1154 } // namespace browser_sync | 1210 } // namespace browser_sync |
OLD | NEW |