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

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

Issue 5705004: [SYNC] Sessions datatype refactor. Most things related to sessions under-the-... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Fix typecasting that windows didn't like Created 10 years 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 (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 <utility> 8 #include <utility>
8 9
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/string_util.h" 11 #include "chrome/browser/browser_list.h"
11 #include "base/utf_string_conversions.h" 12 #include "chrome/browser/browser_window.h"
12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/sessions/session_id.h"
14 #include "chrome/browser/sync/profile_sync_service.h" 14 #include "chrome/browser/sync/profile_sync_service.h"
15 #include "chrome/browser/sync/syncable/syncable.h" 15 #include "chrome/browser/sync/syncable/syncable.h"
16 #include "chrome/browser/tab_contents/navigation_controller.h"
17 #include "chrome/browser/tab_contents/navigation_entry.h"
18 #include "chrome/browser/tabs/tab_strip_model.h"
19 #include "chrome/common/extensions/extension.h"
16 #include "chrome/common/notification_details.h" 20 #include "chrome/common/notification_details.h"
17 #include "chrome/common/notification_service.h" 21 #include "chrome/common/notification_service.h"
18 #include "chrome/common/url_constants.h" 22 #include "chrome/common/url_constants.h"
19 23
20 namespace browser_sync { 24 namespace browser_sync {
21 25
22 namespace { 26 namespace {
23
24 static const char kNoSessionsFolderError[] = 27 static const char kNoSessionsFolderError[] =
25 "Server did not create the top-level sessions node. We " 28 "Server did not create the top-level sessions node. We "
26 "might be running against an out-of-date server."; 29 "might be running against an out-of-date server.";
27 30
31 // The maximum number of navigations in each direction we care to sync.
32 static const int max_sync_navigation_count = 6;
28 } // namespace 33 } // namespace
29 34
30 SessionModelAssociator::SessionModelAssociator( 35 SessionModelAssociator::SessionModelAssociator(ProfileSyncService* sync_service)
31 ProfileSyncService* sync_service) : sync_service_(sync_service) { 36 : tab_pool_fp_(-1),
37 local_session_syncid_(sync_api::kInvalidId),
38 sync_service_(sync_service) {
32 DCHECK(CalledOnValidThread()); 39 DCHECK(CalledOnValidThread());
33 DCHECK(sync_service_); 40 DCHECK(sync_service_);
34 } 41 }
35 42
36 SessionModelAssociator::~SessionModelAssociator() { 43 SessionModelAssociator::~SessionModelAssociator() {
37 DCHECK(CalledOnValidThread()); 44 DCHECK(CalledOnValidThread());
45 DeleteForeignSessions();
38 } 46 }
39 47
40 bool SessionModelAssociator::AssociateModels() { 48 void SessionModelAssociator::DeleteForeignSessions() {
tim (not reviewing) 2010/12/15 21:14:00 should we slap CalledOnValidThread in most of thes
Nicolas Zea 2010/12/16 18:09:18 Why not. On 2010/12/15 21:14:00, timsteele wrote:
41 DCHECK(CalledOnValidThread()); 49 // Delete ForeignSession objects (which also deletes all their windows/tabs).
50 STLDeleteContainerPairSecondPointers(foreign_session_map_.begin(),
51 foreign_session_map_.end());
52 foreign_session_map_.clear();
42 53
43 // Make sure we have a machine tag. 54 // Delete IDToSessTab maps. Does not delete the SessionTab objects, because
44 if (current_machine_tag_.empty()) 55 // they should already be referenced through foreign_session_map_.
45 InitializeCurrentMachineTag(); // Creates a syncable::BaseTransaction. 56 STLDeleteContainerPairSecondPointers(foreign_tab_map_.begin(),
57 foreign_tab_map_.end());
58 foreign_tab_map_.clear();
46 59
47 { 60 // Go through and delete any tabs we had allocated but had not yet placed into
48 // Do an initial update from sync model (in case we just re-enabled and 61 // a ForeignSessionobject.
49 // already had data). 62 STLDeleteContainerPointers(unmapped_tabs_.begin(), unmapped_tabs_.end());
50 sync_api::ReadTransaction trans( 63 unmapped_tabs_.clear();
51 sync_service_->backend()->GetUserShareHandle());
52 UpdateFromSyncModel(&trans);
53 }
54
55 // Check if anything has changed on the client side.
56 UpdateSyncModelDataFromClient();
57 return true;
58 }
59
60 bool SessionModelAssociator::ChromeModelHasUserCreatedNodes(
61 bool* has_nodes) {
62 DCHECK(CalledOnValidThread());
63 CHECK(has_nodes);
64 // This is wrong, but this function is unused, anyway.
65 *has_nodes = true;
66 return true;
67 }
68
69 bool SessionModelAssociator::DisassociateModels() {
70 specifics_.clear();
71
72 // There is no local model stored with which to disassociate, just notify
73 // foreign session handlers.
74 NotificationService::current()->Notify(
75 NotificationType::FOREIGN_SESSION_DISABLED,
76 NotificationService::AllSources(),
77 NotificationService::NoDetails());
78 return true;
79 }
80
81 const sync_pb::SessionSpecifics* SessionModelAssociator::
82 GetChromeNodeFromSyncId(int64 sync_id) {
83 sync_api::ReadTransaction trans(
84 sync_service_->backend()->GetUserShareHandle());
85 sync_api::ReadNode node(&trans);
86 if (!node.InitByIdLookup(sync_id))
87 return NULL;
88 return new sync_pb::SessionSpecifics(node.GetSessionSpecifics());
89 }
90
91 bool SessionModelAssociator::GetSyncIdForTaggedNode(const std::string* tag,
92 int64* sync_id) {
93 sync_api::ReadTransaction trans(
94 sync_service_->backend()->GetUserShareHandle());
95 sync_api::ReadNode node(&trans);
96 if (!node.InitByClientTagLookup(syncable::SESSIONS, *tag))
97 return false;
98 *sync_id = node.GetId();
99 return true;
100 }
101
102 int64 SessionModelAssociator::GetSyncIdFromChromeId(const std::string& id) {
103 sync_api::ReadTransaction trans(
104 sync_service_->backend()->GetUserShareHandle());
105 sync_api::ReadNode node(&trans);
106 if (!node.InitByClientTagLookup(syncable::SESSIONS, id))
107 return sync_api::kInvalidId;
108 return node.GetId();
109 } 64 }
110 65
111 bool SessionModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) { 66 bool SessionModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
112 DCHECK(CalledOnValidThread()); 67 DCHECK(CalledOnValidThread());
113 CHECK(has_nodes); 68 CHECK(has_nodes);
114 *has_nodes = false; 69 *has_nodes = false;
115 sync_api::ReadTransaction trans( 70 sync_api::ReadTransaction trans(
116 sync_service_->backend()->GetUserShareHandle()); 71 sync_service_->backend()->GetUserShareHandle());
117 sync_api::ReadNode root(&trans); 72 sync_api::ReadNode root(&trans);
118 if (!root.InitByTagLookup(kSessionsTag)) { 73 if (!root.InitByTagLookup(kSessionsTag)) {
119 LOG(ERROR) << kNoSessionsFolderError; 74 LOG(ERROR) << kNoSessionsFolderError;
120 return false; 75 return false;
121 } 76 }
122 // The sync model has user created nodes iff the sessions folder has 77 // The sync model has user created nodes iff the sessions folder has
123 // any children. 78 // any children.
124 *has_nodes = root.GetFirstChildId() != sync_api::kInvalidId; 79 *has_nodes = root.GetFirstChildId() != sync_api::kInvalidId;
125 return true; 80 return true;
126 } 81 }
127 82
128 std::string SessionModelAssociator::GetCurrentMachineTag() { 83 int64 SessionModelAssociator::GetSyncIdFromChromeId(const size_t& id) {
129 DCHECK(!current_machine_tag_.empty()); 84 return GetSyncIdFromSessionTag(TabIdToTag(id));
130 return current_machine_tag_;
131 } 85 }
132 86
133 void SessionModelAssociator::UpdateSyncModelDataFromClient() { 87 int64 SessionModelAssociator::GetSyncIdFromSessionTag(const std::string& tag) {
134 DCHECK(CalledOnValidThread()); 88 sync_api::ReadTransaction trans(
135 SessionService::SessionCallback* callback = 89 sync_service_->backend()->GetUserShareHandle());
136 NewCallback(this, &SessionModelAssociator::OnGotSession); 90 sync_api::ReadNode node(&trans);
137 // TODO(jerrica): Stop current race condition, possibly make new method in 91 if (!node.InitByClientTagLookup(syncable::SESSIONS, tag))
138 // session service, which only grabs the windows from memory. 92 return sync_api::kInvalidId;
139 GetSessionService()->GetCurrentSession(&consumer_, callback); 93 return node.GetId();
94 }
95 void SessionModelAssociator::ReassociateWindows(bool reload_tabs) {
96 sync_pb::SessionSpecifics specifics;
97 specifics.set_session_tag(GetCurrentMachineTag());
98 sync_pb::SessionHeader* header_s = specifics.mutable_header();
99
100 for (BrowserList::const_iterator i = BrowserList::begin();
101 i != BrowserList::end(); ++i) {
102 // Make sure the browser has tabs and a window. Browsers destructor
103 // removes itself from the BrowserList. When a browser is closed the
104 // destructor is not necessarily run immediately. This means its possible
105 // for us to get a handle to a browser that is about to be removed. If
106 // the tab count is 0 or the window is NULL, the browser is about to be
107 // deleted, so we ignore it.
108 if (ShouldSyncWindowType((*i)->type()) && (*i)->tab_count() &&
109 (*i)->window()) {
110 sync_pb::SessionWindow window_s;
111 SessionID::id_type window_id = (*i)->session_id().id();
112 VLOG(1) << "Reassociating window " << window_id << " with " <<
113 (*i)->tab_count() << " tabs.";
114 window_s.set_window_id(window_id);
115 window_s.set_selected_tab_index((*i)->selected_index());
116 if ((*i)->type() ==
117 Browser::TYPE_NORMAL) {
118 window_s.set_browser_type(
119 sync_pb::SessionWindow_BrowserType_TYPE_NORMAL);
120 } else {
121 window_s.set_browser_type(
122 sync_pb::SessionWindow_BrowserType_TYPE_POPUP);
123 }
124
125 // Store the order of tabs.
126 bool found_tabs = false;
127 for (int j = 0; j < (*i)->tab_count(); ++j) {
128 TabContents* tab = (*i)->GetTabContentsAt(j);
129 DCHECK(tab);
130 if (IsValidTab(*tab)) {
131 found_tabs = true;
132 window_s.add_tab(tab->controller().session_id().id());
133 if (reload_tabs) {
134 ReassociateTab(*tab);
135 }
136 }
137 }
138 // Only add a window if it contains valid tabs.
139 if (found_tabs) {
140 sync_pb::SessionWindow* header_window = header_s->add_window();
141 *header_window = window_s;
142 }
143 }
144 }
145
146 sync_api::WriteTransaction trans(
147 sync_service_->backend()->GetUserShareHandle());
148 sync_api::WriteNode header_node(&trans);
149 if (!header_node.InitByIdLookup(local_session_syncid_)) {
150 LOG(ERROR) << "Failed to load local session header node.";
151 return;
152 }
153 header_node.SetSessionSpecifics(specifics);
140 } 154 }
141 155
142 // TODO(zea): Don't recreate sessions_ vector from scratch each time. This 156 bool SessionModelAssociator::ShouldSyncWindowType(Browser::Type type) {
143 // will involve knowing which sessions have been changed (a different data 157 switch (type) {
144 // structure will probably be better too). 158 case Browser::TYPE_POPUP:
145 bool SessionModelAssociator::UpdateFromSyncModel( 159 return true;
146 const sync_api::BaseTransaction* trans) { 160 case Browser::TYPE_APP:
147 DCHECK(CalledOnValidThread()); 161 return false;
162 case Browser::TYPE_APP_POPUP:
163 return false;
164 case Browser::TYPE_DEVTOOLS:
165 return false;
166 case Browser::TYPE_APP_PANEL:
167 return false;
168 case Browser::TYPE_NORMAL:
169 default:
170 return true;
171 }
172 }
148 173
149 // Rebuild specifics_ vector 174 void SessionModelAssociator::ReassociateTabs(
150 specifics_.clear(); 175 const std::vector<TabContents*>& tabs) {
151 if (!QuerySyncModel(trans, specifics_)) { 176 for (std::vector<TabContents*>::const_iterator i = tabs.begin();
152 LOG(ERROR) << "SessionModelAssociator failed to updated from sync model"; 177 i != tabs.end();
178 ++i) {
179 ReassociateTab(**i);
180 }
181 }
182
183 void SessionModelAssociator::ReassociateTab(const TabContents& tab) {
184 if (!IsValidTab(tab))
185 return;
186
187 int64 sync_id;
188 SessionID id(tab.controller().session_id());
189
190 TabLinksMap::const_iterator tablink = tab_map_.find(id);
191 if (tablink == tab_map_.end()) {
192 // This is a new tab, get a sync node for it.
193 sync_id = GetFreeTabNode();
194 } else {
195 // This tab is already associated with a sync node, reuse it.
196 sync_id = tablink->second.sync_id();
197 }
198 Associate(&tab, sync_id);
199 }
200
201 void SessionModelAssociator::Associate(const TabContents* tab, int64 sync_id) {
202 TabLinks t(sync_id, tab);
203 SessionID session_id = tab->controller().session_id();
204 tab_map_[session_id] = t;
205
206 sync_api::WriteTransaction trans(
207 sync_service_->backend()->GetUserShareHandle());
208 WriteTabContentsToSyncModel(*tab, sync_id, &trans);
209 }
210
211 bool SessionModelAssociator::WriteTabContentsToSyncModel(
212 const TabContents& tab,
213 int64 sync_id,
214 sync_api::WriteTransaction* trans) {
215 sync_api::WriteNode tab_node(trans);
216 if (!tab_node.InitByIdLookup(sync_id)) {
217 LOG(ERROR) << "Failed to look up tab node " << sync_id;
153 return false; 218 return false;
154 } 219 }
155 220
221 sync_pb::SessionSpecifics session_s;
222 session_s.set_session_tag(GetCurrentMachineTag());
223 sync_pb::SessionTab* tab_s = session_s.mutable_tab();
224
225 SessionID::id_type tab_id = tab.controller().session_id().id();
226 tab_s->set_tab_id(tab_id);
227 tab_s->set_window_id(tab.controller().window_id().id());
228 const int current_index = tab.controller().GetCurrentEntryIndex();
229 const int min_index = std::max(0,
230 current_index - max_sync_navigation_count);
231 const int max_index = std::min(current_index + max_sync_navigation_count,
232 tab.controller().entry_count());
233 const int pending_index = tab.controller().pending_entry_index();
234 Browser* browser = BrowserList::FindBrowserWithID(
235 tab.controller().window_id().id());
236 DCHECK(browser);
237 int index_in_window = browser->tabstrip_model()->GetWrapperIndex(&tab);
238 DCHECK(index_in_window != TabStripModel::kNoTab);
239 tab_s->set_pinned(browser->tabstrip_model()->IsTabPinned(index_in_window));
240 if (tab.extension_app())
241 tab_s->set_extension_app_id(tab.extension_app()->id());
242 for (int i = min_index; i < max_index; ++i) {
243 const NavigationEntry* entry = (i == pending_index) ?
244 tab.controller().pending_entry() : tab.controller().GetEntryAtIndex(i);
245 DCHECK(entry);
246 if (entry->virtual_url().is_valid()) {
247 if (i == max_index-1) {
248 VLOG(1) << "Associating tab " << tab_id << " with sync id " << sync_id
249 << " and url " << entry->virtual_url().possibly_invalid_spec();
250 }
251 TabNavigation tab_nav;
252 tab_nav.SetFromNavigationEntry(*entry);
253 sync_pb::TabNavigation* nav_s = tab_s->add_navigation();
254 PopulateSessionSpecificsNavigation(&tab_nav, nav_s);
255 }
256 }
257 tab_s->set_current_navigation_index(current_index);
258
259 tab_node.SetSessionSpecifics(session_s);
156 return true; 260 return true;
157 } 261 }
158 262
159 bool SessionModelAssociator::QuerySyncModel( 263 // TODO(zea): perhaps sync state (scroll position, form entries, etc.) as well?
tim (not reviewing) 2010/12/15 21:14:00 so far we explicitly didn't want to do this but I
Nicolas Zea 2010/12/16 18:09:18 Done.
160 const sync_api::BaseTransaction* trans,
161 std::vector<const sync_pb::SessionSpecifics*>& specifics) {
162 DCHECK(CalledOnValidThread());
163 sync_api::ReadNode root(trans);
164 if (!root.InitByTagLookup(kSessionsTag)) {
165 LOG(ERROR) << kNoSessionsFolderError;
166 return false;
167 }
168 sync_api::ReadNode current_machine(trans);
169 int64 current_id = (current_machine.InitByClientTagLookup(syncable::SESSIONS,
170 GetCurrentMachineTag())) ? current_machine.GetId() : sync_api::kInvalidId;
171
172 // Iterate through the nodes and populate the session model.
173 int64 id = root.GetFirstChildId();
174 while (id != sync_api::kInvalidId) {
175 sync_api::ReadNode sync_node(trans);
176 if (!sync_node.InitByIdLookup(id)) {
177 LOG(ERROR) << "Failed to fetch sync node for id " << id;
178 return false;
179 }
180 if (id != current_id) {
181 specifics.insert(specifics.end(), &sync_node.GetSessionSpecifics());
182 }
183 id = sync_node.GetSuccessorId();
184 }
185 return true;
186 }
187
188 bool SessionModelAssociator::GetSessionData(
189 std::vector<ForeignSession*>* sessions) {
190 DCHECK(CalledOnValidThread());
191
192 // Build vector of sessions from specifics data
193 for (std::vector<const sync_pb::SessionSpecifics*>::const_iterator i =
194 specifics_.begin(); i != specifics_.end(); ++i) {
195 // Only include sessions with open windows.
196 if ((*i)->session_window_size() > 0)
197 AppendForeignSessionFromSpecifics(*i, sessions);
198 }
199
200 return true;
201 }
202
203 void SessionModelAssociator::AppendForeignSessionFromSpecifics(
204 const sync_pb::SessionSpecifics* specifics,
205 std::vector<ForeignSession*>* session) {
206 ForeignSession* foreign_session = new ForeignSession();
207 foreign_session->foreign_session_tag = specifics->session_tag();
208 session->insert(session->end(), foreign_session);
209 for (int i = 0; i < specifics->session_window_size(); i++) {
210 const sync_pb::SessionWindow* window = &specifics->session_window(i);
211 SessionWindow* session_window = new SessionWindow();
212 PopulateSessionWindowFromSpecifics(session_window, window);
213 foreign_session->windows.insert(
214 foreign_session->windows.end(), session_window);
215 }
216 }
217
218 // Fills the given vector with foreign session windows to restore.
219 void SessionModelAssociator::AppendForeignSessionWithID(int64 id,
220 std::vector<ForeignSession*>* session, sync_api::BaseTransaction* trans) {
221 if (id == sync_api::kInvalidId)
222 return;
223 sync_api::ReadNode node(trans);
224 if (!node.InitByIdLookup(id))
225 return;
226 const sync_pb::SessionSpecifics* ref = &node.GetSessionSpecifics();
227 AppendForeignSessionFromSpecifics(ref, session);
228 }
229
230 SessionService* SessionModelAssociator::GetSessionService() {
231 DCHECK(sync_service_);
232 Profile* profile = sync_service_->profile();
233 DCHECK(profile);
234 SessionService* sessions_service = profile->GetSessionService();
235 DCHECK(sessions_service);
236 return sessions_service;
237 }
238
239 void SessionModelAssociator::InitializeCurrentMachineTag() {
240 sync_api::WriteTransaction trans(sync_service_->backend()->
241 GetUserShareHandle());
242 syncable::Directory* dir =
243 trans.GetWrappedWriteTrans()->directory();
244
245 // TODO(zea): We need a better way of creating a machine tag. The directory
246 // kernel's cache_guid changes every time syncing is turned on and off. This
247 // will result in session's associated with stale machine tags persisting on
248 // the server since that tag will not be reused. Eventually this should
249 // become some string identifiable to the user. (Home, Work, Laptop, etc.)
250 // See issue 59672
251 current_machine_tag_ = "session_sync";
252 current_machine_tag_.append(dir->cache_guid());
253 VLOG(1) << "Creating machine tag: " << current_machine_tag_;
254 }
255
256 // See PopulateSessionSpecificsTab for use. May add functionality that includes
257 // the state later.
258 void SessionModelAssociator::PopulateSessionSpecificsNavigation( 264 void SessionModelAssociator::PopulateSessionSpecificsNavigation(
259 const TabNavigation* navigation, sync_pb::TabNavigation* tab_navigation) { 265 const TabNavigation* navigation,
266 sync_pb::TabNavigation* tab_navigation) {
260 tab_navigation->set_index(navigation->index()); 267 tab_navigation->set_index(navigation->index());
261 tab_navigation->set_virtual_url(navigation->virtual_url().spec()); 268 tab_navigation->set_virtual_url(navigation->virtual_url().spec());
262 tab_navigation->set_referrer(navigation->referrer().spec()); 269 tab_navigation->set_referrer(navigation->referrer().spec());
263 tab_navigation->set_title(UTF16ToUTF8(navigation->title())); 270 tab_navigation->set_title(UTF16ToUTF8(navigation->title()));
264 switch (navigation->transition()) { 271 switch (navigation->transition()) {
265 case PageTransition::LINK: 272 case PageTransition::LINK:
266 tab_navigation->set_page_transition( 273 tab_navigation->set_page_transition(
267 sync_pb::TabNavigation_PageTransition_LINK); 274 sync_pb::TabNavigation_PageTransition_LINK);
268 break; 275 break;
269 case PageTransition::TYPED: 276 case PageTransition::TYPED:
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 case PageTransition::SERVER_REDIRECT: 328 case PageTransition::SERVER_REDIRECT:
322 tab_navigation->set_navigation_qualifier( 329 tab_navigation->set_navigation_qualifier(
323 sync_pb::TabNavigation_PageTransitionQualifier_SERVER_REDIRECT); 330 sync_pb::TabNavigation_PageTransitionQualifier_SERVER_REDIRECT);
324 break; 331 break;
325 default: 332 default:
326 tab_navigation->set_page_transition( 333 tab_navigation->set_page_transition(
327 sync_pb::TabNavigation_PageTransition_TYPED); 334 sync_pb::TabNavigation_PageTransition_TYPED);
328 } 335 }
329 } 336 }
330 337
331 // See PopulateSessionSpecificsWindow for use. 338 void SessionModelAssociator::Disassociate(int64 sync_id) {
332 void SessionModelAssociator::PopulateSessionSpecificsTab( 339 // TODO(zea): we will need this once we support deleting foreign sessions.
tim (not reviewing) 2010/12/15 21:14:00 is it called anywhere? add a NOTIMPLEMENTED() ?
Nicolas Zea 2010/12/16 18:09:18 Done.
333 const SessionTab* tab, sync_pb::SessionTab* session_tab) { 340 }
334 session_tab->set_tab_visual_index(tab->tab_visual_index); 341
335 session_tab->set_current_navigation_index( 342 bool SessionModelAssociator::AssociateModels() {
336 tab->current_navigation_index); 343 DCHECK(CalledOnValidThread());
337 session_tab->set_pinned(tab->pinned); 344
338 session_tab->set_extension_app_id(tab->extension_app_id); 345 // Ensure that we disassociated properly, otherwise memory might leak.
339 for (std::vector<TabNavigation>::const_iterator i3 = 346 DCHECK(foreign_tab_map_.empty());
340 tab->navigations.begin(); i3 != tab->navigations.end(); ++i3) { 347 DCHECK(foreign_session_map_.empty());
341 const TabNavigation navigation = *i3; 348
342 sync_pb::TabNavigation* tab_navigation = 349 // Make sure we have a machine tag.
343 session_tab->add_navigation(); 350 if (current_machine_tag_.empty())
344 PopulateSessionSpecificsNavigation(&navigation, tab_navigation); 351 InitializeCurrentMachineTag(); // Creates a syncable::BaseTransaction.
345 } 352
346 } 353 tab_pool_fp_ = -1;
347 354 local_session_syncid_ = sync_api::kInvalidId;
348 // Called when populating session specifics to send to the sync model, called 355
349 // when associating models, or updating the sync model. 356 // Read any available foreign sessions and load any session data we may have.
350 void SessionModelAssociator::PopulateSessionSpecificsWindow( 357 // If we don't have any local session data in the db, create a header node.
351 const SessionWindow* window, sync_pb::SessionWindow* session_window) { 358 {
352 session_window->set_selected_tab_index(window->selected_tab_index); 359 sync_api::WriteTransaction trans(
353 if (window->type == 1) { 360 sync_service_->backend()->GetUserShareHandle());
354 session_window->set_browser_type( 361
355 sync_pb::SessionWindow_BrowserType_TYPE_NORMAL); 362 sync_api::ReadNode root(&trans);
363 if (!root.InitByTagLookup(kSessionsTag)) {
364 LOG(ERROR) << kNoSessionsFolderError;
365 return false;
366 }
367
368 UpdateAssociationsFromSyncModel(root, &trans);
369
370 if (local_session_syncid_ == sync_api::kInvalidId) {
371 // The sync db didn't have a header node for us, we need to create one.
372 sync_api::WriteNode write_node(&trans);
373 if (!write_node.InitUniqueByCreation(syncable::SESSIONS, root,
374 current_machine_tag_)) {
375 LOG(ERROR) << "Failed to create sessions header sync node.";
376 return false;
377 }
378 write_node.SetTitle(UTF8ToWide(current_machine_tag_));
379 local_session_syncid_ = write_node.GetId();
380 }
381 }
382
383 // Check if anything has changed on the client side.
384 UpdateSyncModelDataFromClient();
385
386 VLOG(1) << "Session models associated.";
387
388 return true;
389 }
390
391 bool SessionModelAssociator::DisassociateModels() {
392 DeleteForeignSessions();
393 tab_map_.clear();
394 tab_syncid_pool_.clear();
395 tab_pool_fp_ = -1;
396 local_session_syncid_ = sync_api::kInvalidId;
397
398 // There is no local model stored with which to disassociate, just notify
399 // foreign session handlers.
400 NotificationService::current()->Notify(
401 NotificationType::FOREIGN_SESSION_DISABLED,
402 NotificationService::AllSources(),
403 NotificationService::NoDetails());
404 return true;
405 }
406
407 void SessionModelAssociator::InitializeCurrentMachineTag() {
408 sync_api::WriteTransaction trans(sync_service_->backend()->
409 GetUserShareHandle());
410 syncable::Directory* dir = trans.GetWrappedWriteTrans()->directory();
411
412 // TODO(zea): We need a better way of creating a machine tag. The directory
tim (not reviewing) 2010/12/15 21:14:00 reference bug #
Nicolas Zea 2010/12/16 18:09:18 See end of comment paragraph. I went ahead and tur
413 // kernel's cache_guid changes every time syncing is turned on and off. This
414 // will result in session's associated with stale machine tags persisting on
415 // the server since that tag will not be reused. Eventually this should
416 // become some string identifiable to the user. (Home, Work, Laptop, etc.)
417 // See issue 59672
418 current_machine_tag_ = "session_sync";
419 current_machine_tag_.append(dir->cache_guid());
420 VLOG(1) << "Creating machine tag: " << current_machine_tag_;
421 }
422
423 bool SessionModelAssociator::UpdateAssociationsFromSyncModel(
424 const sync_api::ReadNode& root,
425 const sync_api::BaseTransaction* trans) {
426 DCHECK(CalledOnValidThread());
427
428 // Iterate through the nodes and associate any foriegn sessions.
429 int64 id = root.GetFirstChildId();
430 while (id != sync_api::kInvalidId) {
431 sync_api::ReadNode sync_node(trans);
432 if (!sync_node.InitByIdLookup(id)) {
433 LOG(ERROR) << "Failed to fetch sync node for id " << id;
434 return false;
435 }
436
437 const sync_pb::SessionSpecifics& specifics =
438 sync_node.GetSessionSpecifics();
439 const int64 modification_time = sync_node.GetModificationTime();
440 if (specifics.session_tag() != GetCurrentMachineTag()) {
441 if (!AssociateForeignSpecifics(specifics, modification_time)) {
442 return false;
443 }
444 } else if (id != local_session_syncid_) {
445 // This is previously stored local session information.
446 if (specifics.has_header()) {
447 DCHECK(local_session_syncid_ == sync_api::kInvalidId);
448
449 // This is our previous header node, reuse it.
450 local_session_syncid_ = id;
451 } else {
452 DCHECK(specifics.has_tab());
453
454 // This is a tab node. We want to track these to reuse them in our free
455 // tab node pool. They will be overwritten eventually, so need to do
456 // anything else.
457 tab_syncid_pool_.push_back(id);
458 tab_pool_fp_++;
459 }
460 }
461
462 id = sync_node.GetSuccessorId();
463 }
464
465 // After updating from sync model all tabid's should be free.
466 DCHECK(tab_pool_fp_ == static_cast<int64>(tab_syncid_pool_.size())-1);
467
468 return true;
469 }
470
471 bool SessionModelAssociator::AssociateForeignSpecifics(
472 const sync_pb::SessionSpecifics& specifics,
473 const int64 modification_time) {
474 std::string foreign_session_tag = specifics.session_tag();
475 DCHECK(foreign_session_tag != GetCurrentMachineTag() ||
476 sync_service_->cros_user() == "test user"); // For tests.
477
478 if (foreign_tab_map_.find(foreign_session_tag) == foreign_tab_map_.end()) {
479 foreign_tab_map_[foreign_session_tag] = new IDToSessTabMap();
480 }
481 if (specifics.has_header()) {
482 // Read in the header data for this foreign session.
483 // Header data contains window information and ordered tab id's for each
484 // window.
485
486 // Load (or create) the ForeignSession object for this client.
487 scoped_ptr<ForeignSession> foreign_session;
488 if (foreign_session_map_.find(foreign_session_tag) !=
489 foreign_session_map_.end()) {
490 foreign_session.reset(foreign_session_map_[foreign_session_tag]);
356 } else { 491 } else {
357 session_window->set_browser_type( 492 foreign_session.reset(new ForeignSession);
358 sync_pb::SessionWindow_BrowserType_TYPE_POPUP); 493 foreign_session->foreign_session_tag = foreign_session_tag;
359 } 494 }
360 for (std::vector<SessionTab*>::const_iterator i2 = window->tabs.begin(); 495
361 i2 != window->tabs.end(); ++i2) { 496 const sync_pb::SessionHeader& header = specifics.header();
362 const SessionTab* tab = *i2; 497 foreign_session->windows.reserve(header.window_size());
363 if (tab->navigations.at(tab->current_navigation_index).virtual_url() == 498 VLOG(1) << "Associating " << foreign_session_tag << " with " <<
364 GURL(chrome::kChromeUINewTabURL)) { 499 header.window_size() << " windows.";
365 continue; 500 size_t i;
501 for (i = 0; i < (size_t)header.window_size(); ++i) {
502 if (i >= foreign_session->windows.size()) {
503 // This a new window, create it.
504 foreign_session->windows.push_back(new SessionWindow());
366 } 505 }
367 sync_pb::SessionTab* session_tab = session_window->add_session_tab(); 506 const sync_pb::SessionWindow& window_s = header.window(i);
368 PopulateSessionSpecificsTab(tab, session_tab); 507 PopulateSessionWindowFromSpecifics(foreign_session_tag,
369 } 508 window_s,
370 } 509 modification_time,
371 510 foreign_session->windows[i]);
372 bool SessionModelAssociator::WindowHasNoTabsToSync( 511 }
373 const SessionWindow* window) { 512 // Remove any remaining windows (in case windows were closed)
374 int num_populated = 0; 513 for (; i < foreign_session->windows.size(); ++i) {
375 for (std::vector<SessionTab*>::const_iterator i = window->tabs.begin(); 514 delete foreign_session->windows[i];
376 i != window->tabs.end(); ++i) { 515 }
377 const SessionTab* tab = *i; 516 foreign_session->windows.resize(header.window_size());
378 if (tab->navigations.at(tab->current_navigation_index).virtual_url() == 517
379 GURL(chrome::kChromeUINewTabURL)) { 518 foreign_session_map_[foreign_session_tag] = foreign_session.release();
380 continue; 519 } else if (specifics.has_tab()) {
381 } 520 const sync_pb::SessionTab& tab_s = specifics.tab();
382 num_populated++; 521 SessionID tab_id(tab_s.tab_id());
383 } 522 scoped_ptr<SessionTab> tab;
384 if (num_populated == 0) 523 if (foreign_tab_map_[foreign_session_tag]->find(tab_id) !=
385 return true; 524 foreign_tab_map_[foreign_session_tag]->end()) {
386 return false; 525 // We've already seen the header for this client, and created the
387 } 526 // appropriate tab objects. Go ahead and fill it with the tab info.
388 527 tab.reset((*foreign_tab_map_[foreign_session_tag])[tab_id]);
389 void SessionModelAssociator::OnGotSession(int handle, 528 unmapped_tabs_.erase(tab.get());
390 std::vector<SessionWindow*>* windows) { 529 VLOG(1) << "Associating " << foreign_session_tag << "'s seen tab " <<
391 sync_pb::SessionSpecifics specifics; 530 tab_id.id() << " at " << tab.get();
392 // Set the tag, then iterate through the vector of windows, extracting the 531 } else {
393 // window data, along with the tabs data and tab navigation data to populate 532 // Create the tab object, and associate it with the tab id in
394 // the session specifics. 533 // |foreign_tab_map_|. It will get associated with a window when we
395 specifics.set_session_tag(GetCurrentMachineTag()); 534 // associate the header node for this client.
396 FillSpecificsFromSessions(windows, &specifics); 535 tab.reset(new SessionTab());
397 bool has_nodes = false; 536 (*foreign_tab_map_[foreign_session_tag])[tab_id] = tab.get();
398 if (!SyncModelHasUserCreatedNodes(&has_nodes)) 537 unmapped_tabs_.insert(tab.get());
399 return; 538 VLOG(1) << "Associating " << foreign_session_tag << "'s new tab " <<
400 if (specifics.session_window_size() == 0 && has_nodes) 539 tab_id.id() << " at " << tab.get();
401 return; 540 }
402 sync_api::WriteTransaction trans( 541 PopulateSessionTabFromSpecifics(tab_s, modification_time, tab.release());
403 sync_service_->backend()->GetUserShareHandle()); 542 } else {
404 sync_api::ReadNode root(&trans); 543 NOTREACHED();
405 if (!root.InitByTagLookup(kSessionsTag)) { 544 return false;
406 LOG(ERROR) << kNoSessionsFolderError; 545 }
407 return; 546
408 } 547 return true;
409 UpdateSyncModel(&specifics, &trans, &root); 548 }
410 } 549
411 550 void SessionModelAssociator::DisassociateForeignSession(
412 void SessionModelAssociator::FillSpecificsFromSessions( 551 const std::string& foreign_session_tag) {
413 std::vector<SessionWindow*>* windows, 552 ForeignSessionMap::iterator iter =
414 sync_pb::SessionSpecifics* session) { 553 foreign_session_map_.find(foreign_session_tag);
415 for (std::vector<SessionWindow*>::const_iterator i = windows->begin(); 554 if (iter != foreign_session_map_.end()) {
416 i != windows->end(); ++i) { 555 delete iter->second; // Delete the ForeignSession object.
417 const SessionWindow* window = *i; 556 foreign_session_map_.erase(iter);
418 if (WindowHasNoTabsToSync(window)) { 557 }
419 continue; 558 }
420 } 559
421 sync_pb::SessionWindow* session_window = session->add_session_window(); 560 void SessionModelAssociator::PopulateSessionWindowFromSpecifics(
422 PopulateSessionSpecificsWindow(window, session_window); 561 std::string foreign_session_tag,
562 const sync_pb::SessionWindow& specifics,
563 int64 mtime,
564 SessionWindow* session_window) {
565 if (specifics.has_window_id())
566 session_window->window_id.set_id(specifics.window_id());
567 if (specifics.has_selected_tab_index())
568 session_window->selected_tab_index = specifics.selected_tab_index();
569 if (specifics.has_browser_type()) {
570 if (specifics.browser_type() ==
571 sync_pb::SessionWindow_BrowserType_TYPE_NORMAL) {
572 session_window->type = 1;
573 } else {
574 session_window->type = 2;
575 }
576 }
577 session_window->timestamp = base::Time::FromInternalValue(mtime);
578 session_window->tabs.resize(specifics.tab_size());
579 for (int i = 0; i < specifics.tab_size(); i++) {
580 SessionID tab_id(specifics.tab(i));
581 scoped_ptr<SessionTab> tab;
582 IDToSessTabMap::iterator iter =
583 foreign_tab_map_[foreign_session_tag]->find(tab_id);
584 if (iter != (*foreign_tab_map_[foreign_session_tag]).end()) {
585 tab.reset(iter->second);
586 unmapped_tabs_.erase(tab.get());
587 VLOG(1) << "Associating " << foreign_session_tag << "'s seen tab " <<
588 tab_id.id() << " at " << tab.get() << " with window " <<
589 specifics.window_id();
590 } else {
591 tab.reset(new SessionTab());
592 (*foreign_tab_map_[foreign_session_tag])[tab_id] = tab.get();
593 unmapped_tabs_.insert(tab.get());
594 VLOG(1) << "Associating " << foreign_session_tag << "'s new tab " <<
595 tab_id.id() << " at " << tab.get() << " with window " <<
596 specifics.window_id();
597 }
598 session_window->tabs[i] = tab.release();
599 }
600 }
601
602 void SessionModelAssociator::PopulateSessionTabFromSpecifics(
603 const sync_pb::SessionTab& specifics,
604 const int64 mtime,
605 SessionTab* tab) {
606 if (specifics.has_tab_id())
607 tab->tab_id.set_id(specifics.tab_id());
608 if (specifics.has_window_id())
609 tab->window_id.set_id(specifics.window_id());
610 if (specifics.has_tab_visual_index())
611 tab->tab_visual_index = specifics.tab_visual_index();
612 if (specifics.has_current_navigation_index())
613 tab->current_navigation_index = specifics.current_navigation_index();
614 if (specifics.has_pinned())
615 tab->pinned = specifics.pinned();
616 if (specifics.has_extension_app_id())
617 tab->extension_app_id = specifics.extension_app_id();
618 tab->timestamp = base::Time::FromInternalValue(mtime);
619 tab->navigations.clear(); // In case we are reusing a previous SessionTab.
620 for (int i = 0; i < specifics.navigation_size(); i++) {
621 AppendSessionTabNavigation(specifics.navigation(i), &tab->navigations);
423 } 622 }
424 } 623 }
425 624
426 void SessionModelAssociator::AppendSessionTabNavigation( 625 void SessionModelAssociator::AppendSessionTabNavigation(
427 std::vector<TabNavigation>* navigations, 626 const sync_pb::TabNavigation& specifics,
428 const sync_pb::TabNavigation* navigation) { 627 std::vector<TabNavigation>* navigations) {
429 int index = 0; 628 int index = 0;
430 GURL virtual_url; 629 GURL virtual_url;
431 GURL referrer; 630 GURL referrer;
432 string16 title; 631 string16 title;
433 std::string state; 632 std::string state;
434 PageTransition::Type transition(PageTransition::LINK); 633 PageTransition::Type transition(PageTransition::LINK);
435 if (navigation->has_index()) 634 if (specifics.has_index())
436 index = navigation->index(); 635 index = specifics.index();
437 if (navigation->has_virtual_url()) { 636 if (specifics.has_virtual_url()) {
438 GURL gurl(navigation->virtual_url()); 637 GURL gurl(specifics.virtual_url());
439 virtual_url = gurl; 638 virtual_url = gurl;
440 } 639 }
441 if (navigation->has_referrer()) { 640 if (specifics.has_referrer()) {
442 GURL gurl(navigation->referrer()); 641 GURL gurl(specifics.referrer());
443 referrer = gurl; 642 referrer = gurl;
444 } 643 }
445 if (navigation->has_title()) 644 if (specifics.has_title())
446 title = UTF8ToUTF16(navigation->title()); 645 title = UTF8ToUTF16(specifics.title());
447 if (navigation->has_page_transition() || 646 if (specifics.has_state())
448 navigation->has_navigation_qualifier()) { 647 state = specifics.state();
449 switch (navigation->page_transition()) { 648 if (specifics.has_page_transition() ||
649 specifics.has_navigation_qualifier()) {
650 switch (specifics.page_transition()) {
450 case sync_pb::TabNavigation_PageTransition_LINK: 651 case sync_pb::TabNavigation_PageTransition_LINK:
451 transition = PageTransition::LINK; 652 transition = PageTransition::LINK;
452 break; 653 break;
453 case sync_pb::TabNavigation_PageTransition_TYPED: 654 case sync_pb::TabNavigation_PageTransition_TYPED:
454 transition = PageTransition::TYPED; 655 transition = PageTransition::TYPED;
455 break; 656 break;
456 case sync_pb::TabNavigation_PageTransition_AUTO_BOOKMARK: 657 case sync_pb::TabNavigation_PageTransition_AUTO_BOOKMARK:
457 transition = PageTransition::AUTO_BOOKMARK; 658 transition = PageTransition::AUTO_BOOKMARK;
458 break; 659 break;
459 case sync_pb::TabNavigation_PageTransition_AUTO_SUBFRAME: 660 case sync_pb::TabNavigation_PageTransition_AUTO_SUBFRAME:
(...skipping 20 matching lines...) Expand all
480 case sync_pb::TabNavigation_PageTransition_KEYWORD_GENERATED: 681 case sync_pb::TabNavigation_PageTransition_KEYWORD_GENERATED:
481 transition = PageTransition::KEYWORD_GENERATED; 682 transition = PageTransition::KEYWORD_GENERATED;
482 break; 683 break;
483 case sync_pb::TabNavigation_PageTransition_CHAIN_START: 684 case sync_pb::TabNavigation_PageTransition_CHAIN_START:
484 transition = sync_pb::TabNavigation_PageTransition_CHAIN_START; 685 transition = sync_pb::TabNavigation_PageTransition_CHAIN_START;
485 break; 686 break;
486 case sync_pb::TabNavigation_PageTransition_CHAIN_END: 687 case sync_pb::TabNavigation_PageTransition_CHAIN_END:
487 transition = PageTransition::CHAIN_END; 688 transition = PageTransition::CHAIN_END;
488 break; 689 break;
489 default: 690 default:
490 switch (navigation->navigation_qualifier()) { 691 switch (specifics.navigation_qualifier()) {
491 case sync_pb:: 692 case sync_pb::
492 TabNavigation_PageTransitionQualifier_CLIENT_REDIRECT: 693 TabNavigation_PageTransitionQualifier_CLIENT_REDIRECT:
493 transition = PageTransition::CLIENT_REDIRECT; 694 transition = PageTransition::CLIENT_REDIRECT;
494 break; 695 break;
495 case sync_pb:: 696 case sync_pb::
496 TabNavigation_PageTransitionQualifier_SERVER_REDIRECT: 697 TabNavigation_PageTransitionQualifier_SERVER_REDIRECT:
497 transition = PageTransition::SERVER_REDIRECT; 698 transition = PageTransition::SERVER_REDIRECT;
498 break; 699 break;
499 default: 700 default:
500 transition = PageTransition::TYPED; 701 transition = PageTransition::TYPED;
501 } 702 }
502 } 703 }
503 } 704 }
504 TabNavigation tab_navigation(index, virtual_url, referrer, title, state, 705 TabNavigation tab_navigation(index, virtual_url, referrer, title, state,
505 transition); 706 transition);
506 navigations->insert(navigations->end(), tab_navigation); 707 navigations->insert(navigations->end(), tab_navigation);
507 } 708 }
508 709
509 void SessionModelAssociator::PopulateSessionTabFromSpecifics( 710 void SessionModelAssociator::UpdateSyncModelDataFromClient() {
510 SessionTab* session_tab, 711 DCHECK(CalledOnValidThread());
511 const sync_pb::SessionTab* tab, SessionID id) { 712 // TODO(zea): the logic for determining if we want to sync and the loading of
512 session_tab->window_id = id; 713 // the previous session should go here. We can probably reuse the code for
513 SessionID tabID; 714 // loading the current session from the old session implementation.
514 session_tab->tab_id = tabID; 715 // SessionService::SessionCallback* callback =
515 if (tab->has_tab_visual_index()) 716 // NewCallback(this, &SessionModelAssociator::OnGotSession);
516 session_tab->tab_visual_index = tab->tab_visual_index(); 717 // GetSessionService()->GetCurrentSession(&consumer_, callback);
517 if (tab->has_current_navigation_index()) { 718
518 session_tab->current_navigation_index = 719 // Associate all open windows and their tabs.
519 tab->current_navigation_index(); 720 ReassociateWindows(true);
520 } 721 }
521 if (tab->has_pinned()) 722
522 session_tab->pinned = tab->pinned(); 723 int64 SessionModelAssociator::GetFreeTabNode() {
523 if (tab->has_extension_app_id()) 724 if (tab_pool_fp_ == -1) {
524 session_tab->extension_app_id = tab->extension_app_id(); 725 // Tab pool has no free nodes, allocate new one.
525 for (int i3 = 0; i3 < tab->navigation_size(); i3++) { 726 sync_api::WriteTransaction trans(
526 const sync_pb::TabNavigation* navigation = &tab->navigation(i3); 727 sync_service_->backend()->GetUserShareHandle());
527 AppendSessionTabNavigation(&session_tab->navigations, navigation); 728 sync_api::ReadNode root(&trans);
528 } 729 if (!root.InitByTagLookup(kSessionsTag)) {
529 } 730 LOG(ERROR) << kNoSessionsFolderError;
530 731 return 0;
531 void SessionModelAssociator::PopulateSessionWindowFromSpecifics( 732 }
532 SessionWindow* session_window, const sync_pb::SessionWindow* window) { 733 size_t tab_node_id = tab_syncid_pool_.size();
533 SessionID id; 734 std::string tab_node_tag = TabIdToTag(tab_node_id);
534 session_window->window_id = id; 735 sync_api::WriteNode tab_node(&trans);
535 if (window->has_selected_tab_index()) 736 if (!tab_node.InitUniqueByCreation(syncable::SESSIONS, root,
536 session_window->selected_tab_index = window->selected_tab_index(); 737 tab_node_tag)) {
537 if (window->has_browser_type()) { 738 LOG(ERROR) << "Could not create node for session " <<
538 if (window->browser_type() == 739 GetCurrentMachineTag();
539 sync_pb::SessionWindow_BrowserType_TYPE_NORMAL) { 740 return -1;
540 session_window->type = 1; 741 }
541 } else { 742 tab_node.SetTitle(UTF8ToWide(tab_node_tag));
542 session_window->type = 2; 743
543 } 744 // Grow the pool by 1 since we created a new node. We don't actually need
544 } 745 // to put the node's id in the pool now, since the pool is still empty.
545 for (int i = 0; i < window->session_tab_size(); i++) { 746 // The id will be added when that tab is closed and the node is freed.
546 const sync_pb::SessionTab& tab = window->session_tab(i); 747 tab_syncid_pool_.resize(tab_node_id + 1);
547 SessionTab* session_tab = new SessionTab(); 748 VLOG(1) << "Adding sync node " << tab_node.GetId() << " to tab syncid pool";
548 PopulateSessionTabFromSpecifics(session_tab, &tab, id); 749 return tab_node.GetId();
549 session_window->tabs.insert(session_window->tabs.end(), session_tab); 750 } else {
550 } 751 // There are nodes available, grab next free and decrement free pointer.
551 } 752 return tab_syncid_pool_[static_cast<size_t>(tab_pool_fp_--)];
552 753 }
553 bool SessionModelAssociator::UpdateSyncModel( 754 }
554 sync_pb::SessionSpecifics* session_data, 755
555 sync_api::WriteTransaction* trans, 756 void SessionModelAssociator::FreeTabNode(int64 sync_id) {
556 const sync_api::ReadNode* root) { 757 // Pool size should always match # of free tab nodes.
557 const std::string id = session_data->session_tag(); 758 DCHECK(tab_pool_fp_ < static_cast<int64>(tab_syncid_pool_.size()));
558 sync_api::WriteNode write_node(trans); 759 tab_syncid_pool_[static_cast<size_t>(++tab_pool_fp_)] = sync_id;
559 if (!write_node.InitByClientTagLookup(syncable::SESSIONS, id)) { 760 }
560 sync_api::WriteNode create_node(trans); 761
561 if (!create_node.InitUniqueByCreation(syncable::SESSIONS, *root, id)) { 762 bool SessionModelAssociator::GetAllForeignSessions(
562 LOG(ERROR) << "Could not create node for session " << id; 763 std::vector<const ForeignSession*>* sessions) {
764 DCHECK(CalledOnValidThread());
765
766 // Build vector of sessions from our foreign session map.
767 for (ForeignSessionMap::const_iterator i =
768 foreign_session_map_.begin(); i != foreign_session_map_.end(); ++i) {
769 // Only include sessions with open tabs.
770 ForeignSession* foreign_session = i->second;
771 if (foreign_session->windows.size() > 0 &&
772 !WindowHasNoTabsToSync(*foreign_session->windows[0]))
773 sessions->push_back(foreign_session);
774 }
775
776 return true;
777 }
778
779 bool SessionModelAssociator::GetForeignSession(
780 const std::string& tag,
781 std::vector<SessionWindow*>* sessions) {
782 DCHECK(CalledOnValidThread());
783
784 ForeignSessionMap::iterator iter = foreign_session_map_.find(tag);
785 if (iter == foreign_session_map_.end())
786 return false;
787 *sessions = iter->second->windows;
788
789 return true;
790 }
791
792 bool SessionModelAssociator::GetForeignTab(
793 const std::string& tag,
794 const SessionID::id_type tab_id,
795 const SessionTab** tab) {
796 if (foreign_tab_map_.find(tag) == foreign_tab_map_.end())
797 return false;
798 SessionID id(tab_id);
799 if (foreign_tab_map_[tag]->find(id) == foreign_tab_map_[tag]->end())
800 return false;
801 *tab = (*foreign_tab_map_[tag])[id];
802 return true;
803 }
804
805 bool SessionModelAssociator::WindowHasNoTabsToSync(
806 const SessionWindow& window) {
807 int num_populated = 0;
808 for (std::vector<SessionTab*>::const_iterator i = window.tabs.begin();
809 i != window.tabs.end(); ++i) {
810 const SessionTab* tab = *i;
811 if (IsValidSessionTab(*tab))
812 num_populated++;
813 }
814 if (num_populated == 0)
815 return true;
816 return false;
817 }
818
819 // Valid local tab?
820 bool SessionModelAssociator::IsValidTab(const TabContents& tab) {
821 if ((tab.profile() == sync_service_->profile() ||
822 sync_service_->profile() == NULL)) {
823 const NavigationEntry* entry = tab.controller().GetActiveEntry();
824 if (!entry)
563 return false; 825 return false;
564 } 826 if (entry->virtual_url().is_valid() &&
565 create_node.SetSessionSpecifics(*session_data); 827 (entry->virtual_url() != GURL(chrome::kChromeUINewTabURL) ||
566 return true; 828 tab.controller().entry_count() > 1)) {
567 } 829 return true;
568 write_node.SetSessionSpecifics(*session_data); 830 }
569 return true; 831 }
832 return false;
833 }
834
835 // Valid foreign tab?
836 bool SessionModelAssociator::IsValidSessionTab(const SessionTab& tab) {
837 if (tab.navigations.empty())
838 return false;
839 int selected_index = tab.current_navigation_index;
840 selected_index = std::max(
841 0,
842 std::min(selected_index,
843 static_cast<int>(tab.navigations.size() - 1)));
844 if (selected_index == 0 &&
845 tab.navigations.size() == 1 &&
846 tab.navigations.at(selected_index).virtual_url() ==
847 GURL(chrome::kChromeUINewTabURL)) {
848 // This is a new tab with no further history, skip.
849 return false;
850 }
851 return true;
852 }
853
854 // ==========================================================================
855 // The following methods are not currently used but will likely become useful
856 // if we choose to sync the previous browser session.
tim (not reviewing) 2010/12/15 21:14:00 previous? is there a bug#?
Nicolas Zea 2010/12/16 18:09:18 No, should I make one? this refers to what Travis
857
858 SessionService* SessionModelAssociator::GetSessionService() {
859 DCHECK(sync_service_);
860 Profile* profile = sync_service_->profile();
861 DCHECK(profile);
862 SessionService* sessions_service = profile->GetSessionService();
863 DCHECK(sessions_service);
864 return sessions_service;
865 }
866
867 void SessionModelAssociator::OnGotSession(
868 int handle,
869 std::vector<SessionWindow*>* windows) {
870 DCHECK(local_session_syncid_);
871
872 sync_pb::SessionSpecifics specifics;
873 specifics.set_session_tag(GetCurrentMachineTag());
874 sync_pb::SessionHeader* header_s = specifics.mutable_header();
875 PopulateSessionSpecificsHeader(*windows, header_s);
876
877 sync_api::WriteTransaction trans(
878 sync_service_->backend()->GetUserShareHandle());
879 sync_api::ReadNode root(&trans);
880 if (!root.InitByTagLookup(kSessionsTag)) {
881 LOG(ERROR) << kNoSessionsFolderError;
882 return;
883 }
884
885 sync_api::WriteNode header_node(&trans);
886 if (!header_node.InitByIdLookup(local_session_syncid_)) {
887 LOG(ERROR) << "Failed to load local session header node.";
888 return;
889 }
890
891 header_node.SetSessionSpecifics(specifics);
892 }
893
894 void SessionModelAssociator::PopulateSessionSpecificsHeader(
895 const std::vector<SessionWindow*>& windows,
896 sync_pb::SessionHeader* header_s) {
897
898 // Iterate through the vector of windows, extracting the window data, along
899 // with the tab data to populate the session specifics.
900 for (size_t i = 0; i < windows.size(); ++i) {
901 if (WindowHasNoTabsToSync(*(windows[i])))
902 continue;
903 sync_pb::SessionWindow* window_s = header_s->add_window();
904 PopulateSessionSpecificsWindow(*(windows[i]), window_s);
905 if (!SyncLocalWindowToSyncModel(*(windows[i])))
906 return;
907 }
908 }
909
910 // Called when populating session specifics to send to the sync model, called
911 // when associating models, or updating the sync model.
912 void SessionModelAssociator::PopulateSessionSpecificsWindow(
913 const SessionWindow& window,
914 sync_pb::SessionWindow* session_window) {
915 session_window->set_window_id(window.window_id.id());
916 session_window->set_selected_tab_index(window.selected_tab_index);
917 if (window.type == Browser::TYPE_NORMAL) {
918 session_window->set_browser_type(
919 sync_pb::SessionWindow_BrowserType_TYPE_NORMAL);
920 } else if (window.type == Browser::TYPE_POPUP) {
921 session_window->set_browser_type(
922 sync_pb::SessionWindow_BrowserType_TYPE_POPUP);
923 } else {
924 // ignore
925 LOG(WARNING) << "Session Sync unable to handle windows of type" <<
926 window.type;
927 return;
928 }
929 for (std::vector<SessionTab*>::const_iterator i = window.tabs.begin();
930 i != window.tabs.end(); ++i) {
931 const SessionTab* tab = *i;
932 if (!IsValidSessionTab(*tab))
933 continue;
934 session_window->add_tab(tab->tab_id.id());
935 }
936 }
937
938 bool SessionModelAssociator::SyncLocalWindowToSyncModel(
939 const SessionWindow& window) {
940 DCHECK(tab_map_.empty());
941 for (size_t i = 0; i < window.tabs.size(); ++i) {
942 SessionTab* tab = window.tabs[i];
943 int64 id = GetFreeTabNode();
944 if (id == -1) {
945 LOG(ERROR) << "Failed to find/generate free sync node for tab.";
946 return false;
947 }
948
949 sync_api::WriteTransaction trans(
950 sync_service_->backend()->GetUserShareHandle());
951 if (!WriteSessionTabToSyncModel(*tab, id, &trans)) {
952 return false;
953 }
954
955 TabLinks t(id, tab);
956 tab_map_[tab->tab_id] = t;
957 }
958 return true;
959 }
960
961 bool SessionModelAssociator::WriteSessionTabToSyncModel(
962 const SessionTab& tab,
963 const int64 sync_id,
964 sync_api::WriteTransaction* trans) {
965 sync_api::WriteNode tab_node(trans);
966 if (!tab_node.InitByIdLookup(sync_id)) {
967 LOG(ERROR) << "Failed to look up tab node " << sync_id;
968 return false;
969 }
970
971 sync_pb::SessionSpecifics specifics;
972 specifics.set_session_tag(GetCurrentMachineTag());
973 sync_pb::SessionTab* tab_s = specifics.mutable_tab();
974 PopulateSessionSpecificsTab(tab, tab_s);
975 tab_node.SetSessionSpecifics(specifics);
976 return true;
977 }
978
979 // See PopulateSessionSpecificsWindow for use.
980 void SessionModelAssociator::PopulateSessionSpecificsTab(
981 const SessionTab& tab,
982 sync_pb::SessionTab* session_tab) {
983 session_tab->set_tab_id(tab.tab_id.id());
984 session_tab->set_window_id(tab.window_id.id());
985 session_tab->set_tab_visual_index(tab.tab_visual_index);
986 session_tab->set_current_navigation_index(
987 tab.current_navigation_index);
988 session_tab->set_pinned(tab.pinned);
989 session_tab->set_extension_app_id(tab.extension_app_id);
990 for (std::vector<TabNavigation>::const_iterator i =
991 tab.navigations.begin(); i != tab.navigations.end(); ++i) {
992 const TabNavigation navigation = *i;
993 sync_pb::TabNavigation* tab_navigation =
994 session_tab->add_navigation();
995 PopulateSessionSpecificsNavigation(&navigation, tab_navigation);
996 }
570 } 997 }
571 998
572 } // namespace browser_sync 999 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698