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

Side by Side Diff: chrome/browser/sync/glue/session_model_associator.cc

Issue 16421003: [Sync] Add logic to reassociate tab nodes after restart. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 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 | Annotate | Revision Log
OLDNEW
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
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;
193 SessionID::id_type window_id = (*i)->GetSessionId(); 194 SessionID::id_type window_id = (*i)->GetSessionId();
194 DVLOG(1) << "Associating window " << window_id << " with " 195 DVLOG(1) << "Associating window " << window_id << " with "
195 << (*i)->GetTabCount() << " tabs."; 196 << (*i)->GetTabCount() << " tabs.";
196 window_s.set_window_id(window_id); 197 window_s.set_window_id(window_id);
197 // Note: We don't bother to set selected tab index anymore. We still 198 // Note: We don't bother to set selected tab index anymore. We still
198 // consume it when receiving foreign sessions, as reading it is free, but 199 // consume it when receiving foreign sessions, as reading it is free, but
199 // it triggers too many sync cycles with too little value to make setting 200 // it triggers too many sync cycles with too little value to make setting
200 // it worthwhile. 201 // it worthwhile.
201 if ((*i)->IsTypeTabbed()) { 202 if ((*i)->IsTypeTabbed()) {
202 window_s.set_browser_type( 203 window_s.set_browser_type(
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 for (int j = 0; j < (*i)->GetTabCount(); ++j) { 211 for (int j = 0; j < (*i)->GetTabCount(); ++j) {
212 SessionID::id_type tab_id = (*i)->GetTabIdAt(j); 212 SessionID::id_type tab_id = (*i)->GetTabIdAt(j);
213 SyncedTabDelegate* syncedTab = (*i)->GetTabAt(j);
Nicolas Zea 2013/06/06 21:27:39 Given your other patch, you probably need to handl
shashi 2013/06/11 19:15:06 Done.
214 if (!syncedTab->HasWebContents()) {
215 // For tabs without webcontents update the tab_id, tab_id could have
216 // changed after a session restore.
217 if (syncedTab->GetSyncId() > 0 &&
Nicolas Zea 2013/06/06 21:27:39 perhaps have GetSyncId() return syncer::kInvalidId
shashi 2013/06/11 19:15:06 kInvalidId, is declared in base_node.h and adding
218 UpdateTabIdIfNeccessary(syncedTab->GetSyncId(), tab_id)) {
Nicolas Zea 2013/06/06 21:27:39 Remind me why we need to update the sync node's id
shashi 2013/06/07 01:44:08 There are two different fields: tab_node_id and ta
Nicolas Zea 2013/06/07 14:42:28 Ah, right, that makes sense.
219 used_sync_ids.insert(syncedTab->GetSyncId());
Nicolas Zea 2013/06/06 21:27:39 shouldn't this always be called? Even if you gener
shashi 2013/06/11 19:15:06 It is also called when we look up for session tab:
220 window_s.add_tab(tab_id);
221 }
222 continue;
223 }
213 224
214 if (reload_tabs) { 225 if (reload_tabs) {
215 SyncedTabDelegate* tab = (*i)->GetTabAt(j);
216 // It's possible for GetTabAt to return a tab which has no web 226 // 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 227 // contents. We can assume this means the tab already existed but
218 // hasn't changed, so no need to reassociate. 228 // hasn't changed, so no need to reassociate.
219 if (tab->HasWebContents() && !AssociateTab(*tab, error)) { 229 if (syncedTab->HasWebContents() && !AssociateTab(syncedTab, error)) {
220 // Association failed. Either we need to re-associate, or this is an 230 // Association failed. Either we need to re-associate, or this is an
221 // unrecoverable error. 231 // unrecoverable error.
222 return false; 232 return false;
223 } 233 }
224 } 234 }
225 235
226 // If the tab is valid, it would have been added to the tracker either 236 // 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 237 // by the above AssociateTab call (at association time), or by the
228 // change processor calling AssociateTab for all modified tabs. 238 // change processor calling AssociateTab for all modified tabs.
229 // Therefore, we can key whether this window has valid tabs based on 239 // Therefore, we can key whether this window has valid tabs based on
230 // the tab's presence in the tracker. 240 // the tab's presence in the tracker.
231 const SessionTab* tab = NULL; 241 const SessionTab* tab = NULL;
232 if (synced_session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) { 242 if (synced_session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) {
233 found_tabs = true; 243 used_sync_ids.insert(syncedTab->GetSyncId());
234 window_s.add_tab(tab_id); 244 window_s.add_tab(tab_id);
235 } 245 }
236 } 246 }
237 // Only add a window if it contains valid tabs. 247 // Only add a window if it contains valid tabs.
238 if (found_tabs) { 248 if (window_s.tab_size() > 0) {
Nicolas Zea 2013/06/06 21:27:39 note that this is going to change behavior. Previo
shashi 2013/06/07 01:44:08 Oh, I thought the found_tabs flag was redundant, i
Nicolas Zea 2013/06/07 14:42:28 LookupSessionTab actually does a validity check fo
shashi 2013/06/11 19:15:06 Reverted. On 2013/06/07 14:42:28, Nicolas Zea wrot
239 sync_pb::SessionWindow* header_window = header_s->add_window(); 249 sync_pb::SessionWindow* header_window = header_s->add_window();
240 *header_window = window_s; 250 *header_window = window_s;
241
242 // Update this window's representation in the synced session tracker. 251 // Update this window's representation in the synced session tracker.
243 synced_session_tracker_.PutWindowInSession(local_tag, window_id); 252 synced_session_tracker_.PutWindowInSession(local_tag, window_id);
244 PopulateSessionWindowFromSpecifics( 253 PopulateSessionWindowFromSpecifics(
245 local_tag, 254 local_tag,
246 window_s, 255 window_s,
247 base::Time::Now(), 256 base::Time::Now(),
248 current_session->windows[window_id], 257 current_session->windows[window_id],
249 &synced_session_tracker_); 258 &synced_session_tracker_);
250 } 259 }
251 } 260 }
252 } 261 }
262
263 // Free old sync nodes.
264 tab_pool_.FreeUnusedOldSyncNodes(used_sync_ids);
Nicolas Zea 2013/06/06 21:27:39 UnusedOld seems a bit redundant. Perhaps FreeUnsyn
shashi 2013/06/11 19:15:06 Done.
253 // Free memory for closed windows and tabs. 265 // Free memory for closed windows and tabs.
254 synced_session_tracker_.CleanupSession(local_tag); 266 synced_session_tracker_.CleanupSession(local_tag);
255 267
256 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); 268 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
257 syncer::WriteNode header_node(&trans); 269 syncer::WriteNode header_node(&trans);
258 if (header_node.InitByIdLookup(local_session_syncid_) != 270 if (header_node.InitByIdLookup(local_session_syncid_) !=
259 syncer::BaseNode::INIT_OK) { 271 syncer::BaseNode::INIT_OK) {
260 if (error) { 272 if (error) {
261 *error = error_handler_->CreateAndUploadError( 273 *error = error_handler_->CreateAndUploadError(
262 FROM_HERE, 274 FROM_HERE,
(...skipping 15 matching lines...) Expand all
278 return window->IsTypeTabbed() || window->IsTypePopup(); 290 return window->IsTypeTabbed() || window->IsTypePopup();
279 } 291 }
280 292
281 bool SessionModelAssociator::AssociateTabs( 293 bool SessionModelAssociator::AssociateTabs(
282 const std::vector<SyncedTabDelegate*>& tabs, 294 const std::vector<SyncedTabDelegate*>& tabs,
283 syncer::SyncError* error) { 295 syncer::SyncError* error) {
284 DCHECK(CalledOnValidThread()); 296 DCHECK(CalledOnValidThread());
285 for (std::vector<SyncedTabDelegate*>::const_iterator i = tabs.begin(); 297 for (std::vector<SyncedTabDelegate*>::const_iterator i = tabs.begin();
286 i != tabs.end(); 298 i != tabs.end();
287 ++i) { 299 ++i) {
288 if (!AssociateTab(**i, error)) 300 if (!AssociateTab(*i, error))
289 return false; 301 return false;
290 } 302 }
291 if (waiting_for_change_) QuitLoopForSubtleTesting(); 303 if (waiting_for_change_) QuitLoopForSubtleTesting();
292 return true; 304 return true;
293 } 305 }
294 306
295 bool SessionModelAssociator::AssociateTab(const SyncedTabDelegate& tab, 307 bool SessionModelAssociator::AssociateTab(SyncedTabDelegate* tab,
296 syncer::SyncError* error) { 308 syncer::SyncError* error) {
297 DCHECK(CalledOnValidThread()); 309 DCHECK(CalledOnValidThread());
310 CHECK(tab);
311 DCHECK(tab->HasWebContents());
298 int64 sync_id; 312 int64 sync_id;
299 SessionID::id_type tab_id = tab.GetSessionId(); 313 SessionID::id_type tab_id = tab->GetSessionId();
300 if (tab.IsBeingDestroyed()) { 314 if (tab->IsBeingDestroyed()) {
301 // This tab is closing. 315 // This tab is closing.
302 TabLinksMap::iterator tab_iter = tab_map_.find(tab_id); 316 TabLinksMap::iterator tab_iter = tab_map_.find(tab_id);
303 if (tab_iter == tab_map_.end()) { 317 if (tab_iter == tab_map_.end()) {
304 // We aren't tracking this tab (for example, sync setting page). 318 // We aren't tracking this tab (for example, sync setting page).
305 return true; 319 return true;
306 } 320 }
307 tab_pool_.FreeTabNode(tab_iter->second->sync_id()); 321 tab_pool_.FreeTabNode(tab_iter->second->sync_id());
308 tab_map_.erase(tab_iter); 322 tab_map_.erase(tab_iter);
309 return true; 323 return true;
310 } 324 }
311 325
312 if (!ShouldSyncTab(tab)) 326 if (!ShouldSyncTab(*tab))
313 return true; 327 return true;
314 328
315 TabLinksMap::iterator tab_map_iter = tab_map_.find(tab_id); 329 TabLinksMap::iterator tab_map_iter = tab_map_.find(tab_id);
316 TabLink* tab_link = NULL; 330 TabLink* tab_link = NULL;
317 if (tab_map_iter == tab_map_.end()) { 331 if (tab_map_iter == tab_map_.end()) {
318 // This is a new tab, get a sync node for it. 332 // if there is an old sync node for the tab, reuse it.
319 sync_id = tab_pool_.GetFreeTabNode(); 333 if (tab_pool_.RemoveIfOldSyncNodeExists(tab->GetSyncId())) {
Nicolas Zea 2013/06/06 21:27:39 This name isn't very clear about what's going on.
shashi 2013/06/11 19:15:06 Hopefully more clear now.
320 if (sync_id == syncer::kInvalidId) { 334 sync_id = tab->GetSyncId();
321 if (error) { 335 } else {
322 *error = error_handler_->CreateAndUploadError( 336 // This is a new tab, get a sync node for it.
323 FROM_HERE, 337 sync_id = tab_pool_.GetFreeTabNode();
324 "Received invalid tab node from tab pool.", 338 if (sync_id == syncer::kInvalidId) {
325 model_type()); 339 if (error) {
340 *error = error_handler_->CreateAndUploadError(
341 FROM_HERE,
342 "Received invalid tab node from tab pool.",
343 model_type());
344 }
345 return false;
326 } 346 }
327 return false;
328 } 347 }
329 tab_link = new TabLink(sync_id, &tab); 348 tab_link = new TabLink(sync_id, tab);
330 tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link); 349 tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link);
350 tab->SetSyncId(sync_id);
331 } else { 351 } else {
332 // This tab is already associated with a sync node, reuse it. 352 // 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 353 // Note: on some platforms the tab object may have changed, so we ensure
334 // the tab link is up to date. 354 // the tab link is up to date.
335 tab_link = tab_map_iter->second.get(); 355 tab_link = tab_map_iter->second.get();
336 tab_map_iter->second->set_tab(&tab); 356 tab_map_iter->second->set_tab(tab);
337 } 357 }
338 DCHECK(tab_link); 358 DCHECK(tab_link);
339 DCHECK_NE(tab_link->sync_id(), syncer::kInvalidId); 359 DCHECK_NE(tab_link->sync_id(), syncer::kInvalidId);
340 360
341 DVLOG(1) << "Reloading tab " << tab_id << " from window " 361 DVLOG(1) << "Reloading tab " << tab_id << " from window "
342 << tab.GetWindowId(); 362 << tab->GetWindowId();
343 return WriteTabContentsToSyncModel(tab_link, error); 363 return WriteTabContentsToSyncModel(tab_link, error);
344 } 364 }
345 365
346 // static 366 // static
347 GURL SessionModelAssociator::GetCurrentVirtualURL( 367 GURL SessionModelAssociator::GetCurrentVirtualURL(
348 const SyncedTabDelegate& tab_delegate) { 368 const SyncedTabDelegate& tab_delegate) {
349 const int current_index = tab_delegate.GetCurrentEntryIndex(); 369 const int current_index = tab_delegate.GetCurrentEntryIndex();
350 const int pending_index = tab_delegate.GetPendingEntryIndex(); 370 const int pending_index = tab_delegate.GetPendingEntryIndex();
351 const NavigationEntry* current_entry = 371 const NavigationEntry* current_entry =
352 (current_index == pending_index) ? 372 (current_index == pending_index) ?
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
724 } else { 744 } else {
725 // This is previously stored local session information. 745 // This is previously stored local session information.
726 if (specifics.has_header() && 746 if (specifics.has_header() &&
727 local_session_syncid_ == syncer::kInvalidId) { 747 local_session_syncid_ == syncer::kInvalidId) {
728 // This is our previous header node, reuse it. 748 // This is our previous header node, reuse it.
729 local_session_syncid_ = id; 749 local_session_syncid_ = id;
730 if (specifics.header().has_client_name()) { 750 if (specifics.header().has_client_name()) {
731 current_session_name_ = specifics.header().client_name(); 751 current_session_name_ = specifics.header().client_name();
732 } 752 }
733 } else { 753 } else {
734 if (specifics.has_header()) { 754 if (specifics.has_header() || !specifics.has_tab() ||
735 LOG(WARNING) << "Found more than one session header node with local " 755 !specifics.has_tab_node_id()) {
736 << " tag."; 756 LOG(WARNING) << "Found invalid session node, deleting.";
737 } else if (!specifics.has_tab()) { 757 sync_node.Tombstone();
738 LOG(WARNING) << "Found local node with no header or tag field."; 758 } else {
759 // This is a valid old tab node, add it to the pool so it can be
760 // reused for reassociation.
761 tab_pool_.AddOldTabNode(id, specifics.tab_node_id());
739 } 762 }
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 } 763 }
746 } 764 }
747 id = next_id; 765 id = next_id;
748 } 766 }
749 767
750 // After updating from sync model all tabid's should be free.
751 DCHECK(tab_pool_.full());
752 return true; 768 return true;
753 } 769 }
754 770
755 void SessionModelAssociator::AssociateForeignSpecifics( 771 void SessionModelAssociator::AssociateForeignSpecifics(
756 const sync_pb::SessionSpecifics& specifics, 772 const sync_pb::SessionSpecifics& specifics,
757 const base::Time& modification_time) { 773 const base::Time& modification_time) {
758 DCHECK(CalledOnValidThread()); 774 DCHECK(CalledOnValidThread());
759 std::string foreign_session_tag = specifics.session_tag(); 775 std::string foreign_session_tag = specifics.session_tag();
760 if (foreign_session_tag == GetCurrentMachineTag() && !setup_for_test_) 776 if (foreign_session_tag == GetCurrentMachineTag() && !setup_for_test_)
761 return; 777 return;
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
1144 } 1160 }
1145 1161
1146 bool SessionModelAssociator::CryptoReadyIfNecessary() { 1162 bool SessionModelAssociator::CryptoReadyIfNecessary() {
1147 // We only access the cryptographer while holding a transaction. 1163 // We only access the cryptographer while holding a transaction.
1148 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); 1164 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
1149 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes(); 1165 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
1150 return !encrypted_types.Has(SESSIONS) || 1166 return !encrypted_types.Has(SESSIONS) ||
1151 sync_service_->IsCryptographerReady(&trans); 1167 sync_service_->IsCryptographerReady(&trans);
1152 } 1168 }
1153 1169
1170 bool SessionModelAssociator::UpdateTabIdIfNeccessary(
1171 int64 sync_id,
1172 SessionID::id_type new_tab_id) {
1173 DCHECK_GT(sync_id, 0);
1174
1175 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
Yaron 2013/06/07 17:08:35 On Android, you're more likely than not to take th
Nicolas Zea 2013/06/07 17:24:04 All transactions involve locking, so yes, they sho
shashi 2013/06/07 19:08:35 Thanks, I am going to try to implement Nicolas' su
shashi 2013/06/11 19:15:06 Instead of adding to SessionTracker, tab_node_pool
1176 syncer::WriteNode tab_node(&trans);
1177 // Rewrite tab id if required.
1178 if (tab_node.InitByIdLookup(sync_id) == syncer::BaseNode::INIT_OK) {
1179 sync_pb::SessionSpecifics session_specifics =
1180 tab_node.GetSessionSpecifics();
1181 DCHECK(session_specifics.has_tab());
1182 if (session_specifics.has_tab()) {
1183 if (session_specifics.tab().tab_id() != new_tab_id) {
1184 sync_pb::SessionTab* tab_s = session_specifics.mutable_tab();
1185 tab_s->set_tab_id(new_tab_id);
1186 tab_node.SetSessionSpecifics(session_specifics);
1187 }
1188 return true;
1189 }
1190 }
1191 return false;
1192 }
1193
1154 } // namespace browser_sync 1194 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698