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

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

Powered by Google App Engine
This is Rietveld 408576698