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

Side by Side Diff: chrome/browser/sessions/session_service.cc

Issue 672083002: Refactoring of SessionService to get componentized. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: One more self nit Created 6 years, 1 month 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sessions/session_service.h" 5 #include "chrome/browser/sessions/session_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 #include <utility> 9 #include <utility>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/bind_helpers.h" 13 #include "base/bind_helpers.h"
14 #include "base/command_line.h" 14 #include "base/command_line.h"
15 #include "base/message_loop/message_loop.h" 15 #include "base/message_loop/message_loop.h"
16 #include "base/metrics/histogram.h" 16 #include "base/metrics/histogram.h"
17 #include "base/pickle.h" 17 #include "base/pickle.h"
18 #include "base/threading/thread.h" 18 #include "base/threading/thread.h"
19 #include "chrome/browser/background/background_mode_manager.h" 19 #include "chrome/browser/background/background_mode_manager.h"
20 #include "chrome/browser/browser_process.h" 20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chrome_notification_types.h" 21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/defaults.h" 22 #include "chrome/browser/defaults.h"
23 #include "chrome/browser/extensions/tab_helper.h" 23 #include "chrome/browser/extensions/tab_helper.h"
24 #include "chrome/browser/prefs/session_startup_pref.h" 24 #include "chrome/browser/prefs/session_startup_pref.h"
25 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/profiles/profile_manager.h" 26 #include "chrome/browser/profiles/profile_manager.h"
27 #include "chrome/browser/sessions/base_session_service_delegate_impl.h" 27 #include "chrome/browser/sessions/base_session_service_delegate_impl.h"
28 #include "chrome/browser/sessions/session_backend.h"
29 #include "chrome/browser/sessions/session_command.h" 28 #include "chrome/browser/sessions/session_command.h"
30 #include "chrome/browser/sessions/session_data_deleter.h" 29 #include "chrome/browser/sessions/session_data_deleter.h"
31 #include "chrome/browser/sessions/session_restore.h" 30 #include "chrome/browser/sessions/session_restore.h"
32 #include "chrome/browser/sessions/session_tab_helper.h" 31 #include "chrome/browser/sessions/session_tab_helper.h"
33 #include "chrome/browser/sessions/session_types.h" 32 #include "chrome/browser/sessions/session_types.h"
34 #include "chrome/browser/ui/browser_iterator.h" 33 #include "chrome/browser/ui/browser_iterator.h"
35 #include "chrome/browser/ui/browser_list.h" 34 #include "chrome/browser/ui/browser_list.h"
36 #include "chrome/browser/ui/browser_tabstrip.h" 35 #include "chrome/browser/ui/browser_tabstrip.h"
37 #include "chrome/browser/ui/browser_window.h" 36 #include "chrome/browser/ui/browser_window.h"
38 #include "chrome/browser/ui/host_desktop.h" 37 #include "chrome/browser/ui/host_desktop.h"
(...skipping 12 matching lines...) Expand all
51 #if defined(OS_MACOSX) 50 #if defined(OS_MACOSX)
52 #include "chrome/browser/app_controller_mac.h" 51 #include "chrome/browser/app_controller_mac.h"
53 #endif 52 #endif
54 53
55 using base::Time; 54 using base::Time;
56 using content::NavigationEntry; 55 using content::NavigationEntry;
57 using content::WebContents; 56 using content::WebContents;
58 using sessions::ContentSerializedNavigationBuilder; 57 using sessions::ContentSerializedNavigationBuilder;
59 using sessions::SerializedNavigationEntry; 58 using sessions::SerializedNavigationEntry;
60 59
61 // Identifier for commands written to file.
62 static const SessionCommand::id_type kCommandSetTabWindow = 0;
63 // OBSOLETE Superseded by kCommandSetWindowBounds3.
64 // static const SessionCommand::id_type kCommandSetWindowBounds = 1;
65 static const SessionCommand::id_type kCommandSetTabIndexInWindow = 2;
66 // OBSOLETE Superseded kCommandTabClosed/kCommandWindowClosed commands.
67 // static const SessionCommand::id_type kCommandTabClosedObsolete = 3;
68 // static const SessionCommand::id_type kCommandWindowClosedObsolete = 4;
69 static const SessionCommand::id_type
70 kCommandTabNavigationPathPrunedFromBack = 5;
71 static const SessionCommand::id_type kCommandUpdateTabNavigation = 6;
72 static const SessionCommand::id_type kCommandSetSelectedNavigationIndex = 7;
73 static const SessionCommand::id_type kCommandSetSelectedTabInIndex = 8;
74 static const SessionCommand::id_type kCommandSetWindowType = 9;
75 // OBSOLETE Superseded by kCommandSetWindowBounds3. Except for data migration.
76 // static const SessionCommand::id_type kCommandSetWindowBounds2 = 10;
77 static const SessionCommand::id_type
78 kCommandTabNavigationPathPrunedFromFront = 11;
79 static const SessionCommand::id_type kCommandSetPinnedState = 12;
80 static const SessionCommand::id_type kCommandSetExtensionAppID = 13;
81 static const SessionCommand::id_type kCommandSetWindowBounds3 = 14;
82 static const SessionCommand::id_type kCommandSetWindowAppName = 15;
83 static const SessionCommand::id_type kCommandTabClosed = 16;
84 static const SessionCommand::id_type kCommandWindowClosed = 17;
85 static const SessionCommand::id_type kCommandSetTabUserAgentOverride = 18;
86 static const SessionCommand::id_type kCommandSessionStorageAssociated = 19;
87 static const SessionCommand::id_type kCommandSetActiveWindow = 20;
88
89 // Every kWritesPerReset commands triggers recreating the file. 60 // Every kWritesPerReset commands triggers recreating the file.
90 static const int kWritesPerReset = 250; 61 static const int kWritesPerReset = 250;
91 62
92 namespace {
93
94 // Various payload structures.
95 struct ClosedPayload {
96 SessionID::id_type id;
97 int64 close_time;
98 };
99
100 struct WindowBoundsPayload2 {
101 SessionID::id_type window_id;
102 int32 x;
103 int32 y;
104 int32 w;
105 int32 h;
106 bool is_maximized;
107 };
108
109 struct WindowBoundsPayload3 {
110 SessionID::id_type window_id;
111 int32 x;
112 int32 y;
113 int32 w;
114 int32 h;
115 int32 show_state;
116 };
117
118 typedef SessionID::id_type ActiveWindowPayload;
119
120 struct IDAndIndexPayload {
121 SessionID::id_type id;
122 int32 index;
123 };
124
125 typedef IDAndIndexPayload TabIndexInWindowPayload;
126
127 typedef IDAndIndexPayload TabNavigationPathPrunedFromBackPayload;
128
129 typedef IDAndIndexPayload SelectedNavigationIndexPayload;
130
131 typedef IDAndIndexPayload SelectedTabInIndexPayload;
132
133 typedef IDAndIndexPayload WindowTypePayload;
134
135 typedef IDAndIndexPayload TabNavigationPathPrunedFromFrontPayload;
136
137 struct PinnedStatePayload {
138 SessionID::id_type tab_id;
139 bool pinned_state;
140 };
141
142 // Persisted versions of ui::WindowShowState that are written to disk and can
143 // never change.
144 enum PersistedWindowShowState {
145 // SHOW_STATE_DEFAULT (0) never persisted.
146 PERSISTED_SHOW_STATE_NORMAL = 1,
147 PERSISTED_SHOW_STATE_MINIMIZED = 2,
148 PERSISTED_SHOW_STATE_MAXIMIZED = 3,
149 // SHOW_STATE_INACTIVE (4) never persisted.
150 PERSISTED_SHOW_STATE_FULLSCREEN = 5,
151 PERSISTED_SHOW_STATE_DETACHED_DEPRECATED = 6,
152 PERSISTED_SHOW_STATE_END = 6
153 };
154
155 // Assert to ensure PersistedWindowShowState is updated if ui::WindowShowState
156 // is changed.
157 COMPILE_ASSERT(ui::SHOW_STATE_END ==
158 static_cast<ui::WindowShowState>(PERSISTED_SHOW_STATE_END),
159 persisted_show_state_mismatch);
160
161 // Returns the show state to store to disk based |state|.
162 PersistedWindowShowState ShowStateToPersistedShowState(
163 ui::WindowShowState state) {
164 switch (state) {
165 case ui::SHOW_STATE_NORMAL:
166 return PERSISTED_SHOW_STATE_NORMAL;
167 case ui::SHOW_STATE_MINIMIZED:
168 return PERSISTED_SHOW_STATE_MINIMIZED;
169 case ui::SHOW_STATE_MAXIMIZED:
170 return PERSISTED_SHOW_STATE_MAXIMIZED;
171 case ui::SHOW_STATE_FULLSCREEN:
172 return PERSISTED_SHOW_STATE_FULLSCREEN;
173
174 case ui::SHOW_STATE_DEFAULT:
175 case ui::SHOW_STATE_INACTIVE:
176 return PERSISTED_SHOW_STATE_NORMAL;
177
178 case ui::SHOW_STATE_END:
179 break;
180 }
181 NOTREACHED();
182 return PERSISTED_SHOW_STATE_NORMAL;
183 }
184
185 // Lints show state values when read back from persited disk.
186 ui::WindowShowState PersistedShowStateToShowState(int state) {
187 switch (state) {
188 case PERSISTED_SHOW_STATE_NORMAL:
189 return ui::SHOW_STATE_NORMAL;
190 case PERSISTED_SHOW_STATE_MINIMIZED:
191 return ui::SHOW_STATE_MINIMIZED;
192 case PERSISTED_SHOW_STATE_MAXIMIZED:
193 return ui::SHOW_STATE_MAXIMIZED;
194 case PERSISTED_SHOW_STATE_FULLSCREEN:
195 return ui::SHOW_STATE_FULLSCREEN;
196 case PERSISTED_SHOW_STATE_DETACHED_DEPRECATED:
197 return ui::SHOW_STATE_NORMAL;
198 }
199 NOTREACHED();
200 return ui::SHOW_STATE_NORMAL;
201 }
202
203 } // namespace
204
205 // SessionService ------------------------------------------------------------- 63 // SessionService -------------------------------------------------------------
206 64
207 SessionService::SessionService(Profile* profile) 65 SessionService::SessionService(Profile* profile)
208 : BaseSessionService( 66 : BaseSessionServiceDelegateImpl(true),
209 SESSION_RESTORE,
210 profile->GetPath(),
211 scoped_ptr<BaseSessionServiceDelegate>(
212 new BaseSessionServiceDelegateImpl(true))),
213 profile_(profile), 67 profile_(profile),
68 session_commands_(new SessionServiceCommands(this)),
69 base_session_service_(
70 new BaseSessionService(BaseSessionService::SESSION_RESTORE,
71 profile->GetPath(),
72 this)),
214 has_open_trackable_browsers_(false), 73 has_open_trackable_browsers_(false),
215 move_on_new_browser_(false), 74 move_on_new_browser_(false),
216 save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)), 75 save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
217 save_delay_in_mins_(base::TimeDelta::FromMinutes(10)), 76 save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
218 save_delay_in_hrs_(base::TimeDelta::FromHours(8)), 77 save_delay_in_hrs_(base::TimeDelta::FromHours(8)),
219 force_browser_not_alive_with_no_windows_(false), 78 force_browser_not_alive_with_no_windows_(false),
220 weak_factory_(this) { 79 weak_factory_(this) {
221 // We should never be created when incognito. 80 // We should never be created when incognito.
222 DCHECK(!profile->IsOffTheRecord()); 81 DCHECK(!profile->IsOffTheRecord());
223 Init(); 82 Init();
224 } 83 }
225 84
226 SessionService::SessionService(const base::FilePath& save_path) 85 SessionService::SessionService(const base::FilePath& save_path)
227 : BaseSessionService( 86 : BaseSessionServiceDelegateImpl(false),
228 SESSION_RESTORE,
229 save_path,
230 scoped_ptr<BaseSessionServiceDelegate>(
231 new BaseSessionServiceDelegateImpl(false))),
232 profile_(NULL), 87 profile_(NULL),
88 session_commands_(new SessionServiceCommands(this)),
89 base_session_service_(
90 new BaseSessionService(BaseSessionService::SESSION_RESTORE,
91 save_path,
92 this)),
233 has_open_trackable_browsers_(false), 93 has_open_trackable_browsers_(false),
234 move_on_new_browser_(false), 94 move_on_new_browser_(false),
235 save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)), 95 save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
236 save_delay_in_mins_(base::TimeDelta::FromMinutes(10)), 96 save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
237 save_delay_in_hrs_(base::TimeDelta::FromHours(8)), 97 save_delay_in_hrs_(base::TimeDelta::FromHours(8)),
238 force_browser_not_alive_with_no_windows_(false), 98 force_browser_not_alive_with_no_windows_(false),
239 weak_factory_(this) { 99 weak_factory_(this) {
240 Init(); 100 Init();
241 } 101 }
242 102
243 SessionService::~SessionService() { 103 SessionService::~SessionService() {
244 // The BrowserList should outlive the SessionService since it's static and 104 // The BrowserList should outlive the SessionService since it's static and
245 // the SessionService is a KeyedService. 105 // the SessionService is a KeyedService.
246 BrowserList::RemoveObserver(this); 106 BrowserList::RemoveObserver(this);
247 Save(); 107 base_session_service_->SaveNow();
108 }
109
110 // static
111 SessionWindow::WindowType SessionService::WindowTypeForBrowserType(
112 Browser::Type type) {
113 switch (type) {
114 case Browser::TYPE_POPUP:
115 return SessionWindow::TYPE_POPUP;
116 case Browser::TYPE_TABBED:
117 return SessionWindow::TYPE_TABBED;
118 default:
119 DCHECK(false);
120 return SessionWindow::TYPE_TABBED;
121 }
122 }
123
124 // static
125 Browser::Type SessionService::BrowserTypeForWindowType(
126 SessionWindow::WindowType type) {
127 switch (type) {
128 case SessionWindow::TYPE_POPUP:
129 return Browser::TYPE_POPUP;
130 case SessionWindow::TYPE_TABBED:
131 default:
132 return Browser::TYPE_TABBED;
133 }
134 }
135
136 bool SessionService::ShouldNewWindowStartSession() {
137 // ChromeOS and OSX have different ideas of application lifetime than
138 // the other platforms.
139 // On ChromeOS opening a new window should never start a new session.
140 #if defined(OS_CHROMEOS)
141 if (!force_browser_not_alive_with_no_windows_)
142 return false;
143 #endif
144 if (!has_open_trackable_browsers_ &&
145 !StartupBrowserCreator::InSynchronousProfileLaunch() &&
146 !SessionRestore::IsRestoring(profile())
147 #if defined(OS_MACOSX)
148 // On OSX, a new window should not start a new session if it was opened
149 // from the dock or the menubar.
150 && !app_controller_mac::IsOpeningNewWindow()
151 #endif // OS_MACOSX
152 ) {
153 return true;
154 }
155 return false;
248 } 156 }
249 157
250 bool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open) { 158 bool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open) {
251 return RestoreIfNecessary(urls_to_open, NULL); 159 return RestoreIfNecessary(urls_to_open, NULL);
252 } 160 }
253 161
254 void SessionService::ResetFromCurrentBrowsers() { 162 void SessionService::ResetFromCurrentBrowsers() {
255 ScheduleReset(); 163 ScheduleResetCommands();
256 } 164 }
257 165
258 void SessionService::MoveCurrentSessionToLastSession() { 166 void SessionService::MoveCurrentSessionToLastSession() {
259 pending_tab_close_ids_.clear(); 167 pending_tab_close_ids_.clear();
260 window_closing_ids_.clear(); 168 window_closing_ids_.clear();
261 pending_window_close_ids_.clear(); 169 pending_window_close_ids_.clear();
262 170
263 Save(); 171 base_session_service_->MoveCurrentSessionToLastSession();
172 }
264 173
265 RunTaskOnBackendThread( 174 void SessionService::DeleteLastSession() {
266 FROM_HERE, base::Bind(&SessionBackend::MoveCurrentSessionToLastSession, 175 base_session_service_->DeleteLastSession();
267 backend()));
268 } 176 }
269 177
270 void SessionService::SetTabWindow(const SessionID& window_id, 178 void SessionService::SetTabWindow(const SessionID& window_id,
271 const SessionID& tab_id) { 179 const SessionID& tab_id) {
272 if (!ShouldTrackChangesToWindow(window_id)) 180 if (!ShouldTrackChangesToWindow(window_id))
273 return; 181 return;
274 182
275 ScheduleCommand(CreateSetTabWindowCommand(window_id, tab_id)); 183 ScheduleCommand(session_commands_->CreateSetTabWindowCommand(
184 window_id,
185 tab_id).Pass());
276 } 186 }
277 187
278 void SessionService::SetWindowBounds(const SessionID& window_id, 188 void SessionService::SetWindowBounds(const SessionID& window_id,
279 const gfx::Rect& bounds, 189 const gfx::Rect& bounds,
280 ui::WindowShowState show_state) { 190 ui::WindowShowState show_state) {
281 if (!ShouldTrackChangesToWindow(window_id)) 191 if (!ShouldTrackChangesToWindow(window_id))
282 return; 192 return;
283 193
284 ScheduleCommand(CreateSetWindowBoundsCommand(window_id, bounds, show_state)); 194 ScheduleCommand(session_commands_->CreateSetWindowBoundsCommand(
195 window_id,
196 bounds, show_state).Pass());
285 } 197 }
286 198
287 void SessionService::SetTabIndexInWindow(const SessionID& window_id, 199 void SessionService::SetTabIndexInWindow(const SessionID& window_id,
288 const SessionID& tab_id, 200 const SessionID& tab_id,
289 int new_index) { 201 int new_index) {
290 if (!ShouldTrackChangesToWindow(window_id)) 202 if (!ShouldTrackChangesToWindow(window_id))
291 return; 203 return;
292 204
293 ScheduleCommand(CreateSetTabIndexInWindowCommand(tab_id, new_index)); 205 ScheduleCommand(session_commands_->CreateSetTabIndexInWindowCommand(
206 tab_id,
207 new_index).Pass());
294 } 208 }
295 209
296 void SessionService::SetPinnedState(const SessionID& window_id, 210 void SessionService::SetPinnedState(const SessionID& window_id,
297 const SessionID& tab_id, 211 const SessionID& tab_id,
298 bool is_pinned) { 212 bool is_pinned) {
299 if (!ShouldTrackChangesToWindow(window_id)) 213 if (!ShouldTrackChangesToWindow(window_id))
300 return; 214 return;
301 215
302 ScheduleCommand(CreatePinnedStateCommand(tab_id, is_pinned)); 216 ScheduleCommand(session_commands_->CreatePinnedStateCommand(
217 tab_id,
218 is_pinned).Pass());
303 } 219 }
304 220
305 void SessionService::TabClosed(const SessionID& window_id, 221 void SessionService::TabClosed(const SessionID& window_id,
306 const SessionID& tab_id, 222 const SessionID& tab_id,
307 bool closed_by_user_gesture) { 223 bool closed_by_user_gesture) {
308 if (!tab_id.id()) 224 if (!tab_id.id())
309 return; // Hapens when the tab is replaced. 225 return; // Hapens when the tab is replaced.
310 226
311 if (!ShouldTrackChangesToWindow(window_id)) 227 if (!ShouldTrackChangesToWindow(window_id))
312 return; 228 return;
(...skipping 10 matching lines...) Expand all
323 pending_tab_close_ids_.insert(tab_id.id()); 239 pending_tab_close_ids_.insert(tab_id.id());
324 } else if (find(window_closing_ids_.begin(), window_closing_ids_.end(), 240 } else if (find(window_closing_ids_.begin(), window_closing_ids_.end(),
325 window_id.id()) != window_closing_ids_.end() || 241 window_id.id()) != window_closing_ids_.end() ||
326 !IsOnlyOneTabLeft() || 242 !IsOnlyOneTabLeft() ||
327 closed_by_user_gesture) { 243 closed_by_user_gesture) {
328 // Close is the result of one of the following: 244 // Close is the result of one of the following:
329 // . window close (and it isn't the last window). 245 // . window close (and it isn't the last window).
330 // . closing a tab and there are other windows/tabs open. 246 // . closing a tab and there are other windows/tabs open.
331 // . closed by a user gesture. 247 // . closed by a user gesture.
332 // In all cases we need to mark the tab as explicitly closed. 248 // In all cases we need to mark the tab as explicitly closed.
333 ScheduleCommand(CreateTabClosedCommand(tab_id.id())); 249 ScheduleCommand(session_commands_->CreateTabClosedCommand(
250 tab_id.id()).Pass());
334 } else { 251 } else {
335 // User closed the last tab in the last tabbed browser. Don't mark the 252 // User closed the last tab in the last tabbed browser. Don't mark the
336 // tab closed. 253 // tab closed.
337 pending_tab_close_ids_.insert(tab_id.id()); 254 pending_tab_close_ids_.insert(tab_id.id());
338 has_open_trackable_browsers_ = false; 255 has_open_trackable_browsers_ = false;
339 } 256 }
340 } 257 }
341 258
342 void SessionService::WindowOpened(Browser* browser) { 259 void SessionService::WindowOpened(Browser* browser) {
343 if (!ShouldTrackBrowser(browser)) 260 if (!ShouldTrackBrowser(browser))
344 return; 261 return;
345 262
346 AppType app_type = browser->is_app() ? TYPE_APP : TYPE_NORMAL; 263 SessionServiceCommands::AppType app_type =
264 browser->is_app() ? SessionServiceCommands::TYPE_APP :
265 SessionServiceCommands::TYPE_NORMAL;
347 RestoreIfNecessary(std::vector<GURL>(), browser); 266 RestoreIfNecessary(std::vector<GURL>(), browser);
348 SetWindowType(browser->session_id(), browser->type(), app_type); 267 SetWindowType(browser->session_id(), browser->type(), app_type);
349 SetWindowAppName(browser->session_id(), browser->app_name()); 268 SetWindowAppName(browser->session_id(), browser->app_name());
350 } 269 }
351 270
352 void SessionService::WindowClosing(const SessionID& window_id) { 271 void SessionService::WindowClosing(const SessionID& window_id) {
353 if (!ShouldTrackChangesToWindow(window_id)) 272 if (!ShouldTrackChangesToWindow(window_id))
354 return; 273 return;
355 274
356 // The window is about to close. If there are other tabbed browsers with the 275 // The window is about to close. If there are other tabbed browsers with the
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 if (!ShouldTrackChangesToWindow(window_id)) { 315 if (!ShouldTrackChangesToWindow(window_id)) {
397 // The last window may be one that is not tracked. 316 // The last window may be one that is not tracked.
398 MaybeDeleteSessionOnlyData(); 317 MaybeDeleteSessionOnlyData();
399 return; 318 return;
400 } 319 }
401 320
402 windows_tracking_.erase(window_id.id()); 321 windows_tracking_.erase(window_id.id());
403 322
404 if (window_closing_ids_.find(window_id.id()) != window_closing_ids_.end()) { 323 if (window_closing_ids_.find(window_id.id()) != window_closing_ids_.end()) {
405 window_closing_ids_.erase(window_id.id()); 324 window_closing_ids_.erase(window_id.id());
406 ScheduleCommand(CreateWindowClosedCommand(window_id.id())); 325 ScheduleCommand(session_commands_->CreateWindowClosedCommand(
326 window_id.id()).Pass());
407 } else if (pending_window_close_ids_.find(window_id.id()) == 327 } else if (pending_window_close_ids_.find(window_id.id()) ==
408 pending_window_close_ids_.end()) { 328 pending_window_close_ids_.end()) {
409 // We'll hit this if user closed the last tab in a window. 329 // We'll hit this if user closed the last tab in a window.
410 has_open_trackable_browsers_ = HasOpenTrackableBrowsers(window_id); 330 has_open_trackable_browsers_ = HasOpenTrackableBrowsers(window_id);
411 if (!has_open_trackable_browsers_) 331 if (!has_open_trackable_browsers_)
412 pending_window_close_ids_.insert(window_id.id()); 332 pending_window_close_ids_.insert(window_id.id());
413 else 333 else
414 ScheduleCommand(CreateWindowClosedCommand(window_id.id())); 334 ScheduleCommand(session_commands_->CreateWindowClosedCommand(
335 window_id.id()).Pass());
415 } 336 }
416 MaybeDeleteSessionOnlyData(); 337 MaybeDeleteSessionOnlyData();
417 } 338 }
418 339
340 void SessionService::TabInserted(WebContents* contents) {
341 SessionTabHelper* session_tab_helper =
342 SessionTabHelper::FromWebContents(contents);
343 if (!ShouldTrackChangesToWindow(session_tab_helper->window_id()))
344 return;
345 SetTabWindow(session_tab_helper->window_id(),
346 session_tab_helper->session_id());
347 extensions::TabHelper* extensions_tab_helper =
348 extensions::TabHelper::FromWebContents(contents);
349 if (extensions_tab_helper &&
350 extensions_tab_helper->extension_app()) {
351 SetTabExtensionAppID(
352 session_tab_helper->window_id(),
353 session_tab_helper->session_id(),
354 extensions_tab_helper->extension_app()->id());
355 }
356
357 // Record the association between the SessionStorageNamespace and the
358 // tab.
359 //
360 // TODO(ajwong): This should be processing the whole map rather than
361 // just the default. This in particular will not work for tabs with only
362 // isolated apps which won't have a default partition.
363 content::SessionStorageNamespace* session_storage_namespace =
364 contents->GetController().GetDefaultSessionStorageNamespace();
365 ScheduleCommand(session_commands_->CreateSessionStorageAssociatedCommand(
366 session_tab_helper->session_id(),
367 session_storage_namespace->persistent_id()));
368 session_storage_namespace->SetShouldPersist(true);
369 }
370
371 void SessionService::TabClosing(WebContents* contents) {
372 // Allow the associated sessionStorage to get deleted; it won't be needed
373 // in the session restore.
374 content::SessionStorageNamespace* session_storage_namespace =
375 contents->GetController().GetDefaultSessionStorageNamespace();
376 session_storage_namespace->SetShouldPersist(false);
377 SessionTabHelper* session_tab_helper =
378 SessionTabHelper::FromWebContents(contents);
379 TabClosed(session_tab_helper->window_id(),
380 session_tab_helper->session_id(),
381 contents->GetClosedByUserGesture());
382 RecordSessionUpdateHistogramData(content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
383 &last_updated_tab_closed_time_);
384 }
385
419 void SessionService::SetWindowType(const SessionID& window_id, 386 void SessionService::SetWindowType(const SessionID& window_id,
420 Browser::Type type, 387 Browser::Type type,
421 AppType app_type) { 388 SessionServiceCommands::AppType app_type) {
422 if (!should_track_changes_for_browser_type(type, app_type)) 389 SessionWindow::WindowType window_type = WindowTypeForBrowserType(type);
390 if (!ShouldRestoreWindowOfType(window_type, app_type))
423 return; 391 return;
424 392
425 windows_tracking_.insert(window_id.id()); 393 windows_tracking_.insert(window_id.id());
426 394
427 // The user created a new tabbed browser with our profile. Commit any 395 // The user created a new tabbed browser with our profile. Commit any
428 // pending closes. 396 // pending closes.
429 CommitPendingCloses(); 397 CommitPendingCloses();
430 398
431 has_open_trackable_browsers_ = true; 399 has_open_trackable_browsers_ = true;
432 move_on_new_browser_ = true; 400 move_on_new_browser_ = true;
433 401
434 ScheduleCommand( 402 ScheduleCommand(session_commands_->CreateSetWindowTypeCommand(
435 CreateSetWindowTypeCommand(window_id, WindowTypeForBrowserType(type))); 403 window_id,
404 window_type).Pass());
436 } 405 }
437 406
438 void SessionService::SetWindowAppName( 407 void SessionService::SetWindowAppName(
439 const SessionID& window_id, 408 const SessionID& window_id,
440 const std::string& app_name) { 409 const std::string& app_name) {
441 if (!ShouldTrackChangesToWindow(window_id)) 410 if (!ShouldTrackChangesToWindow(window_id))
442 return; 411 return;
443 412
444 ScheduleCommand(CreateSetTabExtensionAppIDCommand( 413 ScheduleCommand(session_commands_->CreateSetWindowAppNameCommand(
445 kCommandSetWindowAppName, 414 window_id,
446 window_id.id(), 415 app_name).Pass());
447 app_name));
448 } 416 }
449 417
450 void SessionService::TabNavigationPathPrunedFromBack(const SessionID& window_id, 418 void SessionService::TabNavigationPathPrunedFromBack(const SessionID& window_id,
451 const SessionID& tab_id, 419 const SessionID& tab_id,
452 int count) { 420 int count) {
453 if (!ShouldTrackChangesToWindow(window_id)) 421 if (!ShouldTrackChangesToWindow(window_id))
454 return; 422 return;
455 423
456 TabNavigationPathPrunedFromBackPayload payload = { 0 }; 424 ScheduleCommand(
457 payload.id = tab_id.id(); 425 session_commands_->CreateTabNavigationPathPrunedFromBackCommand(
458 payload.index = count; 426 tab_id, count).Pass());
459 SessionCommand* command =
460 new SessionCommand(kCommandTabNavigationPathPrunedFromBack,
461 sizeof(payload));
462 memcpy(command->contents(), &payload, sizeof(payload));
463 ScheduleCommand(command);
464 } 427 }
465 428
466 void SessionService::TabNavigationPathPrunedFromFront( 429 void SessionService::TabNavigationPathPrunedFromFront(
467 const SessionID& window_id, 430 const SessionID& window_id,
468 const SessionID& tab_id, 431 const SessionID& tab_id,
469 int count) { 432 int count) {
470 if (!ShouldTrackChangesToWindow(window_id)) 433 if (!ShouldTrackChangesToWindow(window_id))
471 return; 434 return;
472 435
473 // Update the range of indices. 436 // Update the range of indices.
474 if (tab_to_available_range_.find(tab_id.id()) != 437 if (tab_to_available_range_.find(tab_id.id()) !=
475 tab_to_available_range_.end()) { 438 tab_to_available_range_.end()) {
476 std::pair<int, int>& range = tab_to_available_range_[tab_id.id()]; 439 std::pair<int, int>& range = tab_to_available_range_[tab_id.id()];
477 range.first = std::max(0, range.first - count); 440 range.first = std::max(0, range.first - count);
478 range.second = std::max(0, range.second - count); 441 range.second = std::max(0, range.second - count);
479 } 442 }
480 443
481 TabNavigationPathPrunedFromFrontPayload payload = { 0 }; 444 ScheduleCommand(
482 payload.id = tab_id.id(); 445 session_commands_->CreateTabNavigationPathPrunedFromFrontCommand(
483 payload.index = count; 446 tab_id,
484 SessionCommand* command = 447 count));
485 new SessionCommand(kCommandTabNavigationPathPrunedFromFront,
486 sizeof(payload));
487 memcpy(command->contents(), &payload, sizeof(payload));
488 ScheduleCommand(command);
489 } 448 }
490 449
491 void SessionService::UpdateTabNavigation( 450 void SessionService::UpdateTabNavigation(
492 const SessionID& window_id, 451 const SessionID& window_id,
493 const SessionID& tab_id, 452 const SessionID& tab_id,
494 const SerializedNavigationEntry& navigation) { 453 const SerializedNavigationEntry& navigation) {
495 if (!ShouldTrackEntry(navigation.virtual_url()) || 454 if (!ShouldTrackEntry(navigation.virtual_url()) ||
496 !ShouldTrackChangesToWindow(window_id)) { 455 !ShouldTrackChangesToWindow(window_id)) {
497 return; 456 return;
498 } 457 }
499 458
500 if (tab_to_available_range_.find(tab_id.id()) != 459 if (tab_to_available_range_.find(tab_id.id()) !=
501 tab_to_available_range_.end()) { 460 tab_to_available_range_.end()) {
502 std::pair<int, int>& range = tab_to_available_range_[tab_id.id()]; 461 std::pair<int, int>& range = tab_to_available_range_[tab_id.id()];
503 range.first = std::min(navigation.index(), range.first); 462 range.first = std::min(navigation.index(), range.first);
504 range.second = std::max(navigation.index(), range.second); 463 range.second = std::max(navigation.index(), range.second);
505 } 464 }
506 ScheduleCommand(CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation, 465 ScheduleCommand(session_commands_->CreateUpdateTabNavigationCommand(
507 tab_id.id(), navigation)); 466 tab_id,
467 navigation).Pass());
508 } 468 }
509 469
510 void SessionService::TabRestored(WebContents* tab, bool pinned) { 470 void SessionService::TabRestored(WebContents* tab, bool pinned) {
511 SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents(tab); 471 SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents(tab);
512 if (!ShouldTrackChangesToWindow(session_tab_helper->window_id())) 472 if (!ShouldTrackChangesToWindow(session_tab_helper->window_id()))
513 return; 473 return;
514 474
515 BuildCommandsForTab(session_tab_helper->window_id(), tab, -1, 475 BuildCommandsForTab(session_tab_helper->window_id(),
516 pinned, &pending_commands(), NULL); 476 tab,
517 StartSaveTimer(); 477 -1,
478 pinned,
479 &base_session_service_->pending_commands(),
480 NULL);
481 base_session_service_->StartSaveTimer();
518 } 482 }
519 483
520 void SessionService::SetSelectedNavigationIndex(const SessionID& window_id, 484 void SessionService::SetSelectedNavigationIndex(const SessionID& window_id,
521 const SessionID& tab_id, 485 const SessionID& tab_id,
522 int index) { 486 int index) {
523 if (!ShouldTrackChangesToWindow(window_id)) 487 if (!ShouldTrackChangesToWindow(window_id))
524 return; 488 return;
525 489
526 if (tab_to_available_range_.find(tab_id.id()) != 490 if (tab_to_available_range_.find(tab_id.id()) !=
527 tab_to_available_range_.end()) { 491 tab_to_available_range_.end()) {
528 if (index < tab_to_available_range_[tab_id.id()].first || 492 if (index < tab_to_available_range_[tab_id.id()].first ||
529 index > tab_to_available_range_[tab_id.id()].second) { 493 index > tab_to_available_range_[tab_id.id()].second) {
530 // The new index is outside the range of what we've archived, schedule 494 // The new index is outside the range of what we've archived, schedule
531 // a reset. 495 // a reset.
532 ResetFromCurrentBrowsers(); 496 ResetFromCurrentBrowsers();
533 return; 497 return;
534 } 498 }
535 } 499 }
536 ScheduleCommand(CreateSetSelectedNavigationIndexCommand(tab_id, index)); 500 ScheduleCommand(session_commands_->CreateSetSelectedNavigationIndexCommand(
501 tab_id,
502 index).Pass());
537 } 503 }
538 504
539 void SessionService::SetSelectedTabInWindow(const SessionID& window_id, 505 void SessionService::SetSelectedTabInWindow(const SessionID& window_id,
540 int index) { 506 int index) {
541 if (!ShouldTrackChangesToWindow(window_id)) 507 if (!ShouldTrackChangesToWindow(window_id))
542 return; 508 return;
543 509
544 ScheduleCommand(CreateSetSelectedTabInWindow(window_id, index)); 510 ScheduleCommand(session_commands_->CreateSetSelectedTabInWindowCommand(
511 window_id,
512 index).Pass());
545 } 513 }
546 514
547 void SessionService::SetTabUserAgentOverride( 515 void SessionService::SetTabUserAgentOverride(
548 const SessionID& window_id, 516 const SessionID& window_id,
549 const SessionID& tab_id, 517 const SessionID& tab_id,
550 const std::string& user_agent_override) { 518 const std::string& user_agent_override) {
551 if (!ShouldTrackChangesToWindow(window_id)) 519 if (!ShouldTrackChangesToWindow(window_id))
552 return; 520 return;
553 521
554 ScheduleCommand(CreateSetTabUserAgentOverrideCommand( 522 ScheduleCommand(session_commands_->CreateSetTabUserAgentOverrideCommand(
555 kCommandSetTabUserAgentOverride, tab_id.id(), user_agent_override)); 523 tab_id,
524 user_agent_override).Pass());
525 }
526
527 void SessionService::SetTabExtensionAppID(
528 const SessionID& window_id,
529 const SessionID& tab_id,
530 const std::string& extension_app_id) {
531 if (!ShouldTrackChangesToWindow(window_id))
532 return;
533
534 ScheduleCommand(session_commands_->CreateSetTabExtensionAppIDCommand(
535 tab_id,
536 extension_app_id).Pass());
556 } 537 }
557 538
558 base::CancelableTaskTracker::TaskId SessionService::GetLastSession( 539 base::CancelableTaskTracker::TaskId SessionService::GetLastSession(
559 const SessionCallback& callback, 540 const SessionCallback& callback,
560 base::CancelableTaskTracker* tracker) { 541 base::CancelableTaskTracker* tracker) {
561 // OnGotSessionCommands maps the SessionCommands to browser state, then run 542 // OnGotSessionCommands maps the SessionCommands to browser state, then run
562 // the callback. 543 // the callback.
563 return ScheduleGetLastSessionCommands( 544 return base_session_service_->ScheduleGetLastSessionCommands(
564 base::Bind(&SessionService::OnGotSessionCommands, 545 base::Bind(&SessionService::OnGotSessionCommands,
565 weak_factory_.GetWeakPtr(), callback), 546 weak_factory_.GetWeakPtr(),
547 callback),
566 tracker); 548 tracker);
567 } 549 }
568 550
569 void SessionService::Save() { 551 bool SessionService::ShouldRestoreWindowOfType(
570 bool had_commands = !pending_commands().empty(); 552 SessionWindow::WindowType window_type,
571 BaseSessionService::Save(); 553 SessionServiceCommands::AppType app_type) const {
572 if (had_commands) { 554 #if defined(OS_CHROMEOS)
573 RecordSessionUpdateHistogramData(chrome::NOTIFICATION_SESSION_SERVICE_SAVED, 555 // Restore app popups for ChromeOS alone.
574 &last_updated_save_time_); 556 if (window_type == SessionWindow::TYPE_POPUP &&
575 content::NotificationService::current()->Notify( 557 app_type == SessionServiceCommands::TYPE_APP)
576 chrome::NOTIFICATION_SESSION_SERVICE_SAVED, 558 return true;
577 content::Source<Profile>(profile()), 559 #endif
578 content::NotificationService::NoDetails()); 560
579 } 561 return window_type == SessionWindow::TYPE_TABBED;
562 }
563
564 void SessionService::OnWillSaveCommands() {}
565
566 void SessionService::OnSavedCommands() {
567 RecordSessionUpdateHistogramData(chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
568 &last_updated_save_time_);
569 content::NotificationService::current()->Notify(
570 chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
571 content::Source<Profile>(profile()),
572 content::NotificationService::NoDetails());
573 }
574
575 SessionServiceCommands* SessionService::GetSessionCommandsForTest() {
576 return session_commands_.get();
577 }
578
579 BaseSessionService* SessionService::GetBaseSessionServiceForTest() {
580 return base_session_service_.get();
580 } 581 }
581 582
582 void SessionService::Init() { 583 void SessionService::Init() {
583 // Register for the notifications we're interested in. 584 // Register for the notifications we're interested in.
584 registrar_.Add(this, content::NOTIFICATION_NAV_LIST_PRUNED, 585 registrar_.Add(this, content::NOTIFICATION_NAV_LIST_PRUNED,
585 content::NotificationService::AllSources()); 586 content::NotificationService::AllSources());
586 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED, 587 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED,
587 content::NotificationService::AllSources()); 588 content::NotificationService::AllSources());
588 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 589 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
589 content::NotificationService::AllSources()); 590 content::NotificationService::AllSources());
590 registrar_.Add( 591 registrar_.Add(
591 this, chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, 592 this, chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
592 content::NotificationService::AllSources()); 593 content::NotificationService::AllSources());
593 594
594 BrowserList::AddObserver(this); 595 BrowserList::AddObserver(this);
595 } 596 }
596 597
597 bool SessionService::processed_any_commands() {
598 return backend()->inited() || !pending_commands().empty();
599 }
600
601 bool SessionService::ShouldNewWindowStartSession() {
602 // ChromeOS and OSX have different ideas of application lifetime than
603 // the other platforms.
604 // On ChromeOS opening a new window should never start a new session.
605 #if defined(OS_CHROMEOS)
606 if (!force_browser_not_alive_with_no_windows_)
607 return false;
608 #endif
609 if (!has_open_trackable_browsers_ &&
610 !StartupBrowserCreator::InSynchronousProfileLaunch() &&
611 !SessionRestore::IsRestoring(profile())
612 #if defined(OS_MACOSX)
613 // On OSX, a new window should not start a new session if it was opened
614 // from the dock or the menubar.
615 && !app_controller_mac::IsOpeningNewWindow()
616 #endif // OS_MACOSX
617 ) {
618 return true;
619 }
620 return false;
621 }
622
623 bool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open, 598 bool SessionService::RestoreIfNecessary(const std::vector<GURL>& urls_to_open,
624 Browser* browser) { 599 Browser* browser) {
625 if (ShouldNewWindowStartSession()) { 600 if (ShouldNewWindowStartSession()) {
626 // We're going from no tabbed browsers to a tabbed browser (and not in 601 // We're going from no tabbed browsers to a tabbed browser (and not in
627 // process startup), restore the last session. 602 // process startup), restore the last session.
628 if (move_on_new_browser_) { 603 if (move_on_new_browser_) {
629 // Make the current session the last. 604 // Make the current session the last.
630 MoveCurrentSessionToLastSession(); 605 MoveCurrentSessionToLastSession();
631 move_on_new_browser_ = false; 606 move_on_new_browser_ = false;
632 } 607 }
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
742 break; 717 break;
743 } 718 }
744 719
745 default: 720 default:
746 NOTREACHED(); 721 NOTREACHED();
747 } 722 }
748 } 723 }
749 724
750 void SessionService::OnBrowserSetLastActive(Browser* browser) { 725 void SessionService::OnBrowserSetLastActive(Browser* browser) {
751 if (ShouldTrackBrowser(browser)) 726 if (ShouldTrackBrowser(browser))
752 ScheduleCommand(CreateSetActiveWindowCommand(browser->session_id())); 727 ScheduleCommand(session_commands_->CreateSetActiveWindowCommand(
753 } 728 browser->session_id()).Pass());
754
755 void SessionService::SetTabExtensionAppID(
756 const SessionID& window_id,
757 const SessionID& tab_id,
758 const std::string& extension_app_id) {
759 if (!ShouldTrackChangesToWindow(window_id))
760 return;
761
762 ScheduleCommand(CreateSetTabExtensionAppIDCommand(kCommandSetExtensionAppID,
763 tab_id.id(), extension_app_id));
764 }
765
766 SessionCommand* SessionService::CreateSetSelectedTabInWindow(
767 const SessionID& window_id,
768 int index) {
769 SelectedTabInIndexPayload payload = { 0 };
770 payload.id = window_id.id();
771 payload.index = index;
772 SessionCommand* command = new SessionCommand(kCommandSetSelectedTabInIndex,
773 sizeof(payload));
774 memcpy(command->contents(), &payload, sizeof(payload));
775 return command;
776 }
777
778 SessionCommand* SessionService::CreateSetTabWindowCommand(
779 const SessionID& window_id,
780 const SessionID& tab_id) {
781 SessionID::id_type payload[] = { window_id.id(), tab_id.id() };
782 SessionCommand* command =
783 new SessionCommand(kCommandSetTabWindow, sizeof(payload));
784 memcpy(command->contents(), payload, sizeof(payload));
785 return command;
786 }
787
788 SessionCommand* SessionService::CreateSetWindowBoundsCommand(
789 const SessionID& window_id,
790 const gfx::Rect& bounds,
791 ui::WindowShowState show_state) {
792 WindowBoundsPayload3 payload = { 0 };
793 payload.window_id = window_id.id();
794 payload.x = bounds.x();
795 payload.y = bounds.y();
796 payload.w = bounds.width();
797 payload.h = bounds.height();
798 payload.show_state = ShowStateToPersistedShowState(show_state);
799 SessionCommand* command = new SessionCommand(kCommandSetWindowBounds3,
800 sizeof(payload));
801 memcpy(command->contents(), &payload, sizeof(payload));
802 return command;
803 }
804
805 SessionCommand* SessionService::CreateSetTabIndexInWindowCommand(
806 const SessionID& tab_id,
807 int new_index) {
808 TabIndexInWindowPayload payload = { 0 };
809 payload.id = tab_id.id();
810 payload.index = new_index;
811 SessionCommand* command =
812 new SessionCommand(kCommandSetTabIndexInWindow, sizeof(payload));
813 memcpy(command->contents(), &payload, sizeof(payload));
814 return command;
815 }
816
817 SessionCommand* SessionService::CreateTabClosedCommand(
818 const SessionID::id_type tab_id) {
819 ClosedPayload payload;
820 // Because of what appears to be a compiler bug setting payload to {0} doesn't
821 // set the padding to 0, resulting in Purify reporting an UMR when we write
822 // the structure to disk. To avoid this we explicitly memset the struct.
823 memset(&payload, 0, sizeof(payload));
824 payload.id = tab_id;
825 payload.close_time = Time::Now().ToInternalValue();
826 SessionCommand* command =
827 new SessionCommand(kCommandTabClosed, sizeof(payload));
828 memcpy(command->contents(), &payload, sizeof(payload));
829 return command;
830 }
831
832 SessionCommand* SessionService::CreateWindowClosedCommand(
833 const SessionID::id_type window_id) {
834 ClosedPayload payload;
835 // See comment in CreateTabClosedCommand as to why we do this.
836 memset(&payload, 0, sizeof(payload));
837 payload.id = window_id;
838 payload.close_time = Time::Now().ToInternalValue();
839 SessionCommand* command =
840 new SessionCommand(kCommandWindowClosed, sizeof(payload));
841 memcpy(command->contents(), &payload, sizeof(payload));
842 return command;
843 }
844
845 SessionCommand* SessionService::CreateSetSelectedNavigationIndexCommand(
846 const SessionID& tab_id,
847 int index) {
848 SelectedNavigationIndexPayload payload = { 0 };
849 payload.id = tab_id.id();
850 payload.index = index;
851 SessionCommand* command = new SessionCommand(
852 kCommandSetSelectedNavigationIndex, sizeof(payload));
853 memcpy(command->contents(), &payload, sizeof(payload));
854 return command;
855 }
856
857 SessionCommand* SessionService::CreateSetWindowTypeCommand(
858 const SessionID& window_id,
859 WindowType type) {
860 WindowTypePayload payload = { 0 };
861 payload.id = window_id.id();
862 payload.index = static_cast<int32>(type);
863 SessionCommand* command = new SessionCommand(
864 kCommandSetWindowType, sizeof(payload));
865 memcpy(command->contents(), &payload, sizeof(payload));
866 return command;
867 }
868
869 SessionCommand* SessionService::CreatePinnedStateCommand(
870 const SessionID& tab_id,
871 bool is_pinned) {
872 PinnedStatePayload payload = { 0 };
873 payload.tab_id = tab_id.id();
874 payload.pinned_state = is_pinned;
875 SessionCommand* command =
876 new SessionCommand(kCommandSetPinnedState, sizeof(payload));
877 memcpy(command->contents(), &payload, sizeof(payload));
878 return command;
879 }
880
881 SessionCommand* SessionService::CreateSessionStorageAssociatedCommand(
882 const SessionID& tab_id,
883 const std::string& session_storage_persistent_id) {
884 Pickle pickle;
885 pickle.WriteInt(tab_id.id());
886 pickle.WriteString(session_storage_persistent_id);
887 return new SessionCommand(kCommandSessionStorageAssociated, pickle);
888 }
889
890 SessionCommand* SessionService::CreateSetActiveWindowCommand(
891 const SessionID& window_id) {
892 ActiveWindowPayload payload = 0;
893 payload = window_id.id();
894 SessionCommand* command =
895 new SessionCommand(kCommandSetActiveWindow, sizeof(payload));
896 memcpy(command->contents(), &payload, sizeof(payload));
897 return command;
898 } 729 }
899 730
900 void SessionService::OnGotSessionCommands( 731 void SessionService::OnGotSessionCommands(
901 const SessionCallback& callback, 732 const SessionCallback& callback,
902 ScopedVector<SessionCommand> commands) { 733 ScopedVector<SessionCommand> commands) {
903 ScopedVector<SessionWindow> valid_windows; 734 ScopedVector<SessionWindow> valid_windows;
904 SessionID::id_type active_window_id = 0; 735 SessionID::id_type active_window_id = 0;
905 736
906 RestoreSessionFromCommands(
907 commands.get(), &valid_windows.get(), &active_window_id);
908 callback.Run(valid_windows.Pass(), active_window_id);
909 }
910
911 void SessionService::RestoreSessionFromCommands(
912 const std::vector<SessionCommand*>& commands,
913 std::vector<SessionWindow*>* valid_windows,
914 SessionID::id_type* active_window_id) {
915 std::map<int, SessionTab*> tabs;
916 std::map<int, SessionWindow*> windows;
917
918 VLOG(1) << "RestoreSessionFromCommands " << commands.size();
919 if (CreateTabsAndWindows(commands, &tabs, &windows, active_window_id)) {
920 AddTabsToWindows(&tabs, &windows);
921 SortTabsBasedOnVisualOrderAndPrune(&windows, valid_windows);
922 UpdateSelectedTabIndex(valid_windows);
923 }
924 STLDeleteValues(&tabs);
925 // Don't delete conents of windows, that is done by the caller as all
926 // valid windows are added to valid_windows.
927 }
928
929 void SessionService::UpdateSelectedTabIndex(
930 std::vector<SessionWindow*>* windows) {
931 for (std::vector<SessionWindow*>::const_iterator i = windows->begin();
932 i != windows->end(); ++i) {
933 // See note in SessionWindow as to why we do this.
934 int new_index = 0;
935 for (std::vector<SessionTab*>::const_iterator j = (*i)->tabs.begin();
936 j != (*i)->tabs.end(); ++j) {
937 if ((*j)->tab_visual_index == (*i)->selected_tab_index) {
938 new_index = static_cast<int>(j - (*i)->tabs.begin());
939 break;
940 }
941 }
942 (*i)->selected_tab_index = new_index;
943 }
944 }
945
946 SessionWindow* SessionService::GetWindow(
947 SessionID::id_type window_id,
948 IdToSessionWindow* windows) {
949 std::map<int, SessionWindow*>::iterator i = windows->find(window_id);
950 if (i == windows->end()) {
951 SessionWindow* window = new SessionWindow();
952 window->window_id.set_id(window_id);
953 (*windows)[window_id] = window;
954 return window;
955 }
956 return i->second;
957 }
958
959 SessionTab* SessionService::GetTab(
960 SessionID::id_type tab_id,
961 IdToSessionTab* tabs) {
962 DCHECK(tabs);
963 std::map<int, SessionTab*>::iterator i = tabs->find(tab_id);
964 if (i == tabs->end()) {
965 SessionTab* tab = new SessionTab();
966 tab->tab_id.set_id(tab_id);
967 (*tabs)[tab_id] = tab;
968 return tab;
969 }
970 return i->second;
971 }
972
973 std::vector<SerializedNavigationEntry>::iterator
974 SessionService::FindClosestNavigationWithIndex(
975 std::vector<SerializedNavigationEntry>* navigations,
976 int index) {
977 DCHECK(navigations);
978 for (std::vector<SerializedNavigationEntry>::iterator
979 i = navigations->begin(); i != navigations->end(); ++i) {
980 if (i->index() >= index)
981 return i;
982 }
983 return navigations->end();
984 }
985
986 // Function used in sorting windows. Sorting is done based on window id. As
987 // window ids increment for each new window, this effectively sorts by creation
988 // time.
989 static bool WindowOrderSortFunction(const SessionWindow* w1,
990 const SessionWindow* w2) {
991 return w1->window_id.id() < w2->window_id.id();
992 }
993
994 // Compares the two tabs based on visual index.
995 static bool TabVisualIndexSortFunction(const SessionTab* t1,
996 const SessionTab* t2) {
997 const int delta = t1->tab_visual_index - t2->tab_visual_index;
998 return delta == 0 ? (t1->tab_id.id() < t2->tab_id.id()) : (delta < 0);
999 }
1000
1001 void SessionService::SortTabsBasedOnVisualOrderAndPrune(
1002 std::map<int, SessionWindow*>* windows,
1003 std::vector<SessionWindow*>* valid_windows) {
1004 std::map<int, SessionWindow*>::iterator i = windows->begin();
1005 while (i != windows->end()) {
1006 SessionWindow* window = i->second;
1007 AppType app_type = window->app_name.empty() ? TYPE_NORMAL : TYPE_APP;
1008 if (window->tabs.empty() || window->is_constrained ||
1009 !should_track_changes_for_browser_type(
1010 static_cast<Browser::Type>(window->type),
1011 app_type)) {
1012 delete window;
1013 windows->erase(i++);
1014 } else {
1015 // Valid window; sort the tabs and add it to the list of valid windows.
1016 std::sort(window->tabs.begin(), window->tabs.end(),
1017 &TabVisualIndexSortFunction);
1018 // Otherwise, add the window such that older windows appear first.
1019 if (valid_windows->empty()) {
1020 valid_windows->push_back(window);
1021 } else {
1022 valid_windows->insert(
1023 std::upper_bound(valid_windows->begin(), valid_windows->end(),
1024 window, &WindowOrderSortFunction),
1025 window);
1026 }
1027 ++i;
1028 }
1029 }
1030 }
1031
1032 void SessionService::AddTabsToWindows(std::map<int, SessionTab*>* tabs,
1033 std::map<int, SessionWindow*>* windows) {
1034 VLOG(1) << "AddTabsToWindws";
1035 VLOG(1) << "Tabs " << tabs->size() << ", windows " << windows->size();
1036 std::map<int, SessionTab*>::iterator i = tabs->begin();
1037 while (i != tabs->end()) {
1038 SessionTab* tab = i->second;
1039 if (tab->window_id.id() && !tab->navigations.empty()) {
1040 SessionWindow* window = GetWindow(tab->window_id.id(), windows);
1041 window->tabs.push_back(tab);
1042 tabs->erase(i++);
1043
1044 // See note in SessionTab as to why we do this.
1045 std::vector<SerializedNavigationEntry>::iterator j =
1046 FindClosestNavigationWithIndex(&(tab->navigations),
1047 tab->current_navigation_index);
1048 if (j == tab->navigations.end()) {
1049 tab->current_navigation_index =
1050 static_cast<int>(tab->navigations.size() - 1);
1051 } else {
1052 tab->current_navigation_index =
1053 static_cast<int>(j - tab->navigations.begin());
1054 }
1055 } else {
1056 // Never got a set tab index in window, or tabs are empty, nothing
1057 // to do.
1058 ++i;
1059 }
1060 }
1061 }
1062
1063 bool SessionService::CreateTabsAndWindows(
1064 const std::vector<SessionCommand*>& data,
1065 std::map<int, SessionTab*>* tabs,
1066 std::map<int, SessionWindow*>* windows,
1067 SessionID::id_type* active_window_id) {
1068 // If the file is corrupt (command with wrong size, or unknown command), we
1069 // still return true and attempt to restore what we we can.
1070 VLOG(1) << "CreateTabsAndWindows";
1071
1072 startup_metric_utils::ScopedSlowStartupUMA 737 startup_metric_utils::ScopedSlowStartupUMA
1073 scoped_timer("Startup.SlowStartupSessionServiceCreateTabsAndWindows"); 738 scoped_timer("Startup.SlowStartupSessionServiceCreateTabsAndWindows");
1074 739
1075 for (std::vector<SessionCommand*>::const_iterator i = data.begin(); 740 session_commands_->RestoreSessionFromCommands(
1076 i != data.end(); ++i) { 741 commands, &valid_windows.get(), &active_window_id);
1077 const SessionCommand::id_type kCommandSetWindowBounds2 = 10; 742 callback.Run(valid_windows.Pass(), active_window_id);
1078 const SessionCommand* command = *i;
1079
1080 VLOG(1) << "Read command " << (int) command->id();
1081 switch (command->id()) {
1082 case kCommandSetTabWindow: {
1083 SessionID::id_type payload[2];
1084 if (!command->GetPayload(payload, sizeof(payload))) {
1085 VLOG(1) << "Failed reading command " << command->id();
1086 return true;
1087 }
1088 GetTab(payload[1], tabs)->window_id.set_id(payload[0]);
1089 break;
1090 }
1091
1092 // This is here for forward migration only. New data is saved with
1093 // |kCommandSetWindowBounds3|.
1094 case kCommandSetWindowBounds2: {
1095 WindowBoundsPayload2 payload;
1096 if (!command->GetPayload(&payload, sizeof(payload))) {
1097 VLOG(1) << "Failed reading command " << command->id();
1098 return true;
1099 }
1100 GetWindow(payload.window_id, windows)->bounds.SetRect(payload.x,
1101 payload.y,
1102 payload.w,
1103 payload.h);
1104 GetWindow(payload.window_id, windows)->show_state =
1105 payload.is_maximized ?
1106 ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL;
1107 break;
1108 }
1109
1110 case kCommandSetWindowBounds3: {
1111 WindowBoundsPayload3 payload;
1112 if (!command->GetPayload(&payload, sizeof(payload))) {
1113 VLOG(1) << "Failed reading command " << command->id();
1114 return true;
1115 }
1116 GetWindow(payload.window_id, windows)->bounds.SetRect(payload.x,
1117 payload.y,
1118 payload.w,
1119 payload.h);
1120 GetWindow(payload.window_id, windows)->show_state =
1121 PersistedShowStateToShowState(payload.show_state);
1122 break;
1123 }
1124
1125 case kCommandSetTabIndexInWindow: {
1126 TabIndexInWindowPayload payload;
1127 if (!command->GetPayload(&payload, sizeof(payload))) {
1128 VLOG(1) << "Failed reading command " << command->id();
1129 return true;
1130 }
1131 GetTab(payload.id, tabs)->tab_visual_index = payload.index;
1132 break;
1133 }
1134
1135 case kCommandTabClosed:
1136 case kCommandWindowClosed: {
1137 ClosedPayload payload;
1138 if (!command->GetPayload(&payload, sizeof(payload))) {
1139 VLOG(1) << "Failed reading command " << command->id();
1140 return true;
1141 }
1142 if (command->id() == kCommandTabClosed) {
1143 delete GetTab(payload.id, tabs);
1144 tabs->erase(payload.id);
1145 } else {
1146 delete GetWindow(payload.id, windows);
1147 windows->erase(payload.id);
1148 }
1149 break;
1150 }
1151
1152 case kCommandTabNavigationPathPrunedFromBack: {
1153 TabNavigationPathPrunedFromBackPayload payload;
1154 if (!command->GetPayload(&payload, sizeof(payload))) {
1155 VLOG(1) << "Failed reading command " << command->id();
1156 return true;
1157 }
1158 SessionTab* tab = GetTab(payload.id, tabs);
1159 tab->navigations.erase(
1160 FindClosestNavigationWithIndex(&(tab->navigations), payload.index),
1161 tab->navigations.end());
1162 break;
1163 }
1164
1165 case kCommandTabNavigationPathPrunedFromFront: {
1166 TabNavigationPathPrunedFromFrontPayload payload;
1167 if (!command->GetPayload(&payload, sizeof(payload)) ||
1168 payload.index <= 0) {
1169 VLOG(1) << "Failed reading command " << command->id();
1170 return true;
1171 }
1172 SessionTab* tab = GetTab(payload.id, tabs);
1173
1174 // Update the selected navigation index.
1175 tab->current_navigation_index =
1176 std::max(-1, tab->current_navigation_index - payload.index);
1177
1178 // And update the index of existing navigations.
1179 for (std::vector<SerializedNavigationEntry>::iterator
1180 i = tab->navigations.begin();
1181 i != tab->navigations.end();) {
1182 i->set_index(i->index() - payload.index);
1183 if (i->index() < 0)
1184 i = tab->navigations.erase(i);
1185 else
1186 ++i;
1187 }
1188 break;
1189 }
1190
1191 case kCommandUpdateTabNavigation: {
1192 SerializedNavigationEntry navigation;
1193 SessionID::id_type tab_id;
1194 if (!RestoreUpdateTabNavigationCommand(
1195 *command, &navigation, &tab_id)) {
1196 VLOG(1) << "Failed reading command " << command->id();
1197 return true;
1198 }
1199 SessionTab* tab = GetTab(tab_id, tabs);
1200 std::vector<SerializedNavigationEntry>::iterator i =
1201 FindClosestNavigationWithIndex(&(tab->navigations),
1202 navigation.index());
1203 if (i != tab->navigations.end() && i->index() == navigation.index())
1204 *i = navigation;
1205 else
1206 tab->navigations.insert(i, navigation);
1207 break;
1208 }
1209
1210 case kCommandSetSelectedNavigationIndex: {
1211 SelectedNavigationIndexPayload payload;
1212 if (!command->GetPayload(&payload, sizeof(payload))) {
1213 VLOG(1) << "Failed reading command " << command->id();
1214 return true;
1215 }
1216 GetTab(payload.id, tabs)->current_navigation_index = payload.index;
1217 break;
1218 }
1219
1220 case kCommandSetSelectedTabInIndex: {
1221 SelectedTabInIndexPayload payload;
1222 if (!command->GetPayload(&payload, sizeof(payload))) {
1223 VLOG(1) << "Failed reading command " << command->id();
1224 return true;
1225 }
1226 GetWindow(payload.id, windows)->selected_tab_index = payload.index;
1227 break;
1228 }
1229
1230 case kCommandSetWindowType: {
1231 WindowTypePayload payload;
1232 if (!command->GetPayload(&payload, sizeof(payload))) {
1233 VLOG(1) << "Failed reading command " << command->id();
1234 return true;
1235 }
1236 GetWindow(payload.id, windows)->is_constrained = false;
1237 GetWindow(payload.id, windows)->type =
1238 BrowserTypeForWindowType(
1239 static_cast<WindowType>(payload.index));
1240 break;
1241 }
1242
1243 case kCommandSetPinnedState: {
1244 PinnedStatePayload payload;
1245 if (!command->GetPayload(&payload, sizeof(payload))) {
1246 VLOG(1) << "Failed reading command " << command->id();
1247 return true;
1248 }
1249 GetTab(payload.tab_id, tabs)->pinned = payload.pinned_state;
1250 break;
1251 }
1252
1253 case kCommandSetWindowAppName: {
1254 SessionID::id_type window_id;
1255 std::string app_name;
1256 if (!RestoreSetWindowAppNameCommand(*command, &window_id, &app_name))
1257 return true;
1258
1259 GetWindow(window_id, windows)->app_name.swap(app_name);
1260 break;
1261 }
1262
1263 case kCommandSetExtensionAppID: {
1264 SessionID::id_type tab_id;
1265 std::string extension_app_id;
1266 if (!RestoreSetTabExtensionAppIDCommand(
1267 *command, &tab_id, &extension_app_id)) {
1268 VLOG(1) << "Failed reading command " << command->id();
1269 return true;
1270 }
1271
1272 GetTab(tab_id, tabs)->extension_app_id.swap(extension_app_id);
1273 break;
1274 }
1275
1276 case kCommandSetTabUserAgentOverride: {
1277 SessionID::id_type tab_id;
1278 std::string user_agent_override;
1279 if (!RestoreSetTabUserAgentOverrideCommand(
1280 *command, &tab_id, &user_agent_override)) {
1281 return true;
1282 }
1283
1284 GetTab(tab_id, tabs)->user_agent_override.swap(user_agent_override);
1285 break;
1286 }
1287
1288 case kCommandSessionStorageAssociated: {
1289 scoped_ptr<Pickle> command_pickle(command->PayloadAsPickle());
1290 SessionID::id_type command_tab_id;
1291 std::string session_storage_persistent_id;
1292 PickleIterator iter(*command_pickle.get());
1293 if (!command_pickle->ReadInt(&iter, &command_tab_id) ||
1294 !command_pickle->ReadString(&iter, &session_storage_persistent_id))
1295 return true;
1296 // Associate the session storage back.
1297 GetTab(command_tab_id, tabs)->session_storage_persistent_id =
1298 session_storage_persistent_id;
1299 break;
1300 }
1301
1302 case kCommandSetActiveWindow: {
1303 ActiveWindowPayload payload;
1304 if (!command->GetPayload(&payload, sizeof(payload))) {
1305 VLOG(1) << "Failed reading command " << command->id();
1306 return true;
1307 }
1308 *active_window_id = payload;
1309 break;
1310 }
1311
1312 default:
1313 VLOG(1) << "Failed reading an unknown command " << command->id();
1314 return true;
1315 }
1316 }
1317 return true;
1318 } 743 }
1319 744
1320 void SessionService::BuildCommandsForTab(const SessionID& window_id, 745 void SessionService::BuildCommandsForTab(const SessionID& window_id,
1321 WebContents* tab, 746 WebContents* tab,
1322 int index_in_window, 747 int index_in_window,
1323 bool is_pinned, 748 bool is_pinned,
1324 std::vector<SessionCommand*>* commands, 749 ScopedVector<SessionCommand>* commands,
1325 IdToRange* tab_to_available_range) { 750 IdToRange* tab_to_available_range) {
1326 DCHECK(tab && commands && window_id.id()); 751 DCHECK(tab && commands && window_id.id());
1327 SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents(tab); 752 SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents(tab);
1328 const SessionID& session_id(session_tab_helper->session_id()); 753 const SessionID& session_id(session_tab_helper->session_id());
1329 commands->push_back(CreateSetTabWindowCommand(window_id, session_id)); 754 commands->push_back(session_commands_->CreateSetTabWindowCommand(
755 window_id,
756 session_id).release());
1330 757
1331 const int current_index = tab->GetController().GetCurrentEntryIndex(); 758 const int current_index = tab->GetController().GetCurrentEntryIndex();
1332 const int min_index = std::max(0, 759 const int min_index =
1333 current_index - max_persist_navigation_count); 760 std::max(current_index - BaseSessionService::max_persist_navigation_count,
761 0);
1334 const int max_index = 762 const int max_index =
1335 std::min(current_index + max_persist_navigation_count, 763 std::min(current_index + BaseSessionService::max_persist_navigation_count,
1336 tab->GetController().GetEntryCount()); 764 tab->GetController().GetEntryCount());
1337 const int pending_index = tab->GetController().GetPendingEntryIndex(); 765 const int pending_index = tab->GetController().GetPendingEntryIndex();
1338 if (tab_to_available_range) { 766 if (tab_to_available_range) {
1339 (*tab_to_available_range)[session_id.id()] = 767 (*tab_to_available_range)[session_id.id()] =
1340 std::pair<int, int>(min_index, max_index); 768 std::pair<int, int>(min_index, max_index);
1341 } 769 }
1342 770
1343 if (is_pinned) { 771 if (is_pinned) {
1344 commands->push_back(CreatePinnedStateCommand(session_id, true)); 772 commands->push_back(session_commands_->CreatePinnedStateCommand(
773 session_id,
774 true).release());
1345 } 775 }
1346 776
1347 extensions::TabHelper* extensions_tab_helper = 777 extensions::TabHelper* extensions_tab_helper =
1348 extensions::TabHelper::FromWebContents(tab); 778 extensions::TabHelper::FromWebContents(tab);
1349 if (extensions_tab_helper->extension_app()) { 779 if (extensions_tab_helper->extension_app()) {
1350 commands->push_back( 780 commands->push_back(session_commands_->CreateSetTabExtensionAppIDCommand(
1351 CreateSetTabExtensionAppIDCommand( 781 session_id,
1352 kCommandSetExtensionAppID, session_id.id(), 782 extensions_tab_helper->extension_app()->id()).release());
1353 extensions_tab_helper->extension_app()->id()));
1354 } 783 }
1355 784
1356 const std::string& ua_override = tab->GetUserAgentOverride(); 785 const std::string& ua_override = tab->GetUserAgentOverride();
1357 if (!ua_override.empty()) { 786 if (!ua_override.empty()) {
1358 commands->push_back( 787 commands->push_back(
1359 CreateSetTabUserAgentOverrideCommand( 788 session_commands_->CreateSetTabUserAgentOverrideCommand(
1360 kCommandSetTabUserAgentOverride, session_id.id(), ua_override)); 789 session_id,
790 ua_override).release());
1361 } 791 }
1362 792
1363 for (int i = min_index; i < max_index; ++i) { 793 for (int i = min_index; i < max_index; ++i) {
1364 const NavigationEntry* entry = (i == pending_index) ? 794 const NavigationEntry* entry = (i == pending_index) ?
1365 tab->GetController().GetPendingEntry() : 795 tab->GetController().GetPendingEntry() :
1366 tab->GetController().GetEntryAtIndex(i); 796 tab->GetController().GetEntryAtIndex(i);
1367 DCHECK(entry); 797 DCHECK(entry);
1368 if (ShouldTrackEntry(entry->GetVirtualURL())) { 798 if (ShouldTrackEntry(entry->GetVirtualURL())) {
1369 const SerializedNavigationEntry navigation = 799 const SerializedNavigationEntry navigation =
1370 ContentSerializedNavigationBuilder::FromNavigationEntry(i, *entry); 800 ContentSerializedNavigationBuilder::FromNavigationEntry(i, *entry);
1371 commands->push_back( 801 commands->push_back(session_commands_->CreateUpdateTabNavigationCommand(
1372 CreateUpdateTabNavigationCommand( 802 session_id,
1373 kCommandUpdateTabNavigation, session_id.id(), navigation)); 803 navigation).release());
1374 } 804 }
1375 } 805 }
1376 commands->push_back( 806 commands->push_back(
1377 CreateSetSelectedNavigationIndexCommand(session_id, current_index)); 807 session_commands_->CreateSetSelectedNavigationIndexCommand(
808 session_id,
809 current_index).release());
1378 810
1379 if (index_in_window != -1) { 811 if (index_in_window != -1) {
1380 commands->push_back( 812 commands->push_back(session_commands_->CreateSetTabIndexInWindowCommand(
1381 CreateSetTabIndexInWindowCommand(session_id, index_in_window)); 813 session_id,
814 index_in_window).release());
1382 } 815 }
1383 816
1384 // Record the association between the sessionStorage namespace and the tab. 817 // Record the association between the sessionStorage namespace and the tab.
1385 content::SessionStorageNamespace* session_storage_namespace = 818 content::SessionStorageNamespace* session_storage_namespace =
1386 tab->GetController().GetDefaultSessionStorageNamespace(); 819 tab->GetController().GetDefaultSessionStorageNamespace();
1387 ScheduleCommand(CreateSessionStorageAssociatedCommand( 820 ScheduleCommand(session_commands_->CreateSessionStorageAssociatedCommand(
1388 session_tab_helper->session_id(), 821 session_tab_helper->session_id(),
1389 session_storage_namespace->persistent_id())); 822 session_storage_namespace->persistent_id()));
1390 } 823 }
1391 824
1392 void SessionService::BuildCommandsForBrowser( 825 void SessionService::BuildCommandsForBrowser(
1393 Browser* browser, 826 Browser* browser,
1394 std::vector<SessionCommand*>* commands, 827 ScopedVector<SessionCommand>* commands,
1395 IdToRange* tab_to_available_range, 828 IdToRange* tab_to_available_range,
1396 std::set<SessionID::id_type>* windows_to_track) { 829 std::set<SessionID::id_type>* windows_to_track) {
1397 DCHECK(browser && commands); 830 DCHECK(browser && commands);
1398 DCHECK(browser->session_id().id()); 831 DCHECK(browser->session_id().id());
1399 832
1400 commands->push_back( 833 commands->push_back(session_commands_->CreateSetWindowBoundsCommand(
1401 CreateSetWindowBoundsCommand(browser->session_id(), 834 browser->session_id(),
1402 browser->window()->GetRestoredBounds(), 835 browser->window()->GetRestoredBounds(),
1403 browser->window()->GetRestoredState())); 836 browser->window()->GetRestoredState()).release());
1404 837
1405 commands->push_back(CreateSetWindowTypeCommand( 838 commands->push_back(session_commands_->CreateSetWindowTypeCommand(
1406 browser->session_id(), WindowTypeForBrowserType(browser->type()))); 839 browser->session_id(),
840 WindowTypeForBrowserType(browser->type())).release());
1407 841
1408 if (!browser->app_name().empty()) { 842 if (!browser->app_name().empty()) {
1409 commands->push_back(CreateSetWindowAppNameCommand( 843 commands->push_back(session_commands_->CreateSetWindowAppNameCommand(
1410 kCommandSetWindowAppName, 844 browser->session_id(),
1411 browser->session_id().id(), 845 browser->app_name()).release());
1412 browser->app_name()));
1413 } 846 }
1414 847
1415 windows_to_track->insert(browser->session_id().id()); 848 windows_to_track->insert(browser->session_id().id());
1416 TabStripModel* tab_strip = browser->tab_strip_model(); 849 TabStripModel* tab_strip = browser->tab_strip_model();
1417 for (int i = 0; i < tab_strip->count(); ++i) { 850 for (int i = 0; i < tab_strip->count(); ++i) {
1418 WebContents* tab = tab_strip->GetWebContentsAt(i); 851 WebContents* tab = tab_strip->GetWebContentsAt(i);
1419 DCHECK(tab); 852 DCHECK(tab);
1420 BuildCommandsForTab(browser->session_id(), tab, i, 853 BuildCommandsForTab(browser->session_id(), tab, i,
1421 tab_strip->IsTabPinned(i), 854 tab_strip->IsTabPinned(i),
1422 commands, tab_to_available_range); 855 commands, tab_to_available_range);
1423 } 856 }
1424 857
1425 commands->push_back( 858 commands->push_back(
1426 CreateSetSelectedTabInWindow(browser->session_id(), 859 session_commands_->CreateSetSelectedTabInWindowCommand(
1427 browser->tab_strip_model()->active_index())); 860 browser->session_id(),
861 browser->tab_strip_model()->active_index()).release());
1428 } 862 }
1429 863
1430 void SessionService::BuildCommandsFromBrowsers( 864 void SessionService::BuildCommandsFromBrowsers(
1431 std::vector<SessionCommand*>* commands, 865 ScopedVector<SessionCommand>* commands,
1432 IdToRange* tab_to_available_range, 866 IdToRange* tab_to_available_range,
1433 std::set<SessionID::id_type>* windows_to_track) { 867 std::set<SessionID::id_type>* windows_to_track) {
1434 DCHECK(commands); 868 DCHECK(commands);
1435 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 869 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1436 Browser* browser = *it; 870 Browser* browser = *it;
1437 // Make sure the browser has tabs and a window. Browser's destructor 871 // Make sure the browser has tabs and a window. Browser's destructor
1438 // removes itself from the BrowserList. When a browser is closed the 872 // removes itself from the BrowserList. When a browser is closed the
1439 // destructor is not necessarily run immediately. This means it's possible 873 // destructor is not necessarily run immediately. This means it's possible
1440 // for us to get a handle to a browser that is about to be removed. If 874 // for us to get a handle to a browser that is about to be removed. If
1441 // the tab count is 0 or the window is NULL, the browser is about to be 875 // the tab count is 0 or the window is NULL, the browser is about to be
1442 // deleted, so we ignore it. 876 // deleted, so we ignore it.
1443 if (ShouldTrackBrowser(browser) && browser->tab_strip_model()->count() && 877 if (ShouldTrackBrowser(browser) && browser->tab_strip_model()->count() &&
1444 browser->window()) { 878 browser->window()) {
1445 BuildCommandsForBrowser(browser, commands, tab_to_available_range, 879 BuildCommandsForBrowser(browser, commands, tab_to_available_range,
1446 windows_to_track); 880 windows_to_track);
1447 } 881 }
1448 } 882 }
1449 } 883 }
1450 884
1451 void SessionService::ScheduleReset() { 885 void SessionService::ScheduleResetCommands() {
1452 set_pending_reset(true); 886 base_session_service_->set_pending_reset(true);
1453 STLDeleteElements(&pending_commands()); 887 STLDeleteElements(&base_session_service_->pending_commands());
1454 tab_to_available_range_.clear(); 888 tab_to_available_range_.clear();
1455 windows_tracking_.clear(); 889 windows_tracking_.clear();
1456 BuildCommandsFromBrowsers(&pending_commands(), &tab_to_available_range_, 890 BuildCommandsFromBrowsers(&base_session_service_->pending_commands(),
891 &tab_to_available_range_,
1457 &windows_tracking_); 892 &windows_tracking_);
1458 if (!windows_tracking_.empty()) { 893 if (!windows_tracking_.empty()) {
1459 // We're lazily created on startup and won't get an initial batch of 894 // We're lazily created on startup and won't get an initial batch of
1460 // SetWindowType messages. Set these here to make sure our state is correct. 895 // SetWindowType messages. Set these here to make sure our state is correct.
1461 has_open_trackable_browsers_ = true; 896 has_open_trackable_browsers_ = true;
1462 move_on_new_browser_ = true; 897 move_on_new_browser_ = true;
1463 } 898 }
1464 StartSaveTimer(); 899 base_session_service_->StartSaveTimer();
1465 } 900 }
1466 901
1467 bool SessionService::ReplacePendingCommand(SessionCommand* command) { 902 void SessionService::ScheduleCommand(scoped_ptr<SessionCommand> command) {
1468 // We optimize page navigations, which can happen quite frequently and 903 DCHECK(command);
1469 // are expensive. And activation is like Highlander, there can only be one! 904 if (session_commands_->ReplacePendingCommand(
1470 if (command->id() != kCommandUpdateTabNavigation && 905 &command,
1471 command->id() != kCommandSetActiveWindow) { 906 base_session_service_->pending_commands())) {
1472 return false; 907 return;
1473 } 908 }
1474 for (std::vector<SessionCommand*>::reverse_iterator i = 909 bool is_closing_command = session_commands_->IsClosingCommand(command.get());
1475 pending_commands().rbegin(); i != pending_commands().rend(); ++i) { 910 // Do the actual work.
1476 SessionCommand* existing_command = *i; 911 base_session_service_->ScheduleCommand(command.Pass());
1477 if (command->id() == kCommandUpdateTabNavigation &&
1478 existing_command->id() == kCommandUpdateTabNavigation) {
1479 scoped_ptr<Pickle> command_pickle(command->PayloadAsPickle());
1480 PickleIterator iterator(*command_pickle);
1481 SessionID::id_type command_tab_id;
1482 int command_nav_index;
1483 if (!command_pickle->ReadInt(&iterator, &command_tab_id) ||
1484 !command_pickle->ReadInt(&iterator, &command_nav_index)) {
1485 return false;
1486 }
1487 SessionID::id_type existing_tab_id;
1488 int existing_nav_index;
1489 {
1490 // Creating a pickle like this means the Pickle references the data from
1491 // the command. Make sure we delete the pickle before the command, else
1492 // the pickle references deleted memory.
1493 scoped_ptr<Pickle> existing_pickle(existing_command->PayloadAsPickle());
1494 iterator = PickleIterator(*existing_pickle);
1495 if (!existing_pickle->ReadInt(&iterator, &existing_tab_id) ||
1496 !existing_pickle->ReadInt(&iterator, &existing_nav_index)) {
1497 return false;
1498 }
1499 }
1500 if (existing_tab_id == command_tab_id &&
1501 existing_nav_index == command_nav_index) {
1502 // existing_command is an update for the same tab/index pair. Replace
1503 // it with the new one. We need to add to the end of the list just in
1504 // case there is a prune command after the update command.
1505 delete existing_command;
1506 pending_commands().erase(i.base() - 1);
1507 pending_commands().push_back(command);
1508 return true;
1509 }
1510 return false;
1511 }
1512 if (command->id() == kCommandSetActiveWindow &&
1513 existing_command->id() == kCommandSetActiveWindow) {
1514 *i = command;
1515 delete existing_command;
1516 return true;
1517 }
1518 }
1519 return false;
1520 }
1521
1522 void SessionService::ScheduleCommand(SessionCommand* command) {
1523 DCHECK(command);
1524 if (ReplacePendingCommand(command))
1525 return;
1526 BaseSessionService::ScheduleCommand(command);
1527 // Don't schedule a reset on tab closed/window closed. Otherwise we may 912 // Don't schedule a reset on tab closed/window closed. Otherwise we may
1528 // lose tabs/windows we want to restore from if we exit right after this. 913 // lose tabs/windows we want to restore from if we exit right after this.
1529 if (!pending_reset() && pending_window_close_ids_.empty() && 914 if (!base_session_service_->pending_reset() &&
1530 commands_since_reset() >= kWritesPerReset && 915 pending_window_close_ids_.empty() &&
1531 (command->id() != kCommandTabClosed && 916 base_session_service_->commands_since_reset() >= kWritesPerReset &&
1532 command->id() != kCommandWindowClosed)) { 917 !is_closing_command) {
1533 ScheduleReset(); 918 ScheduleResetCommands();
1534 } 919 }
1535 } 920 }
1536 921
1537 void SessionService::CommitPendingCloses() { 922 void SessionService::CommitPendingCloses() {
1538 for (PendingTabCloseIDs::iterator i = pending_tab_close_ids_.begin(); 923 for (PendingTabCloseIDs::iterator i = pending_tab_close_ids_.begin();
1539 i != pending_tab_close_ids_.end(); ++i) { 924 i != pending_tab_close_ids_.end(); ++i) {
1540 ScheduleCommand(CreateTabClosedCommand(*i)); 925 ScheduleCommand(session_commands_->CreateTabClosedCommand(*i));
1541 } 926 }
1542 pending_tab_close_ids_.clear(); 927 pending_tab_close_ids_.clear();
1543 928
1544 for (PendingWindowCloseIDs::iterator i = pending_window_close_ids_.begin(); 929 for (PendingWindowCloseIDs::iterator i = pending_window_close_ids_.begin();
1545 i != pending_window_close_ids_.end(); ++i) { 930 i != pending_window_close_ids_.end(); ++i) {
1546 ScheduleCommand(CreateWindowClosedCommand(*i)); 931 ScheduleCommand(session_commands_->CreateWindowClosedCommand(*i));
1547 } 932 }
1548 pending_window_close_ids_.clear(); 933 pending_window_close_ids_.clear();
1549 } 934 }
1550 935
1551 bool SessionService::IsOnlyOneTabLeft() const { 936 bool SessionService::IsOnlyOneTabLeft() const {
1552 if (!profile() || profile()->AsTestingProfile()) { 937 if (!profile() || profile()->AsTestingProfile()) {
1553 // We're testing, always return false. 938 // We're testing, always return false.
1554 return false; 939 return false;
1555 } 940 }
1556 941
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1598 bool SessionService::ShouldTrackBrowser(Browser* browser) const { 983 bool SessionService::ShouldTrackBrowser(Browser* browser) const {
1599 if (browser->profile() != profile()) 984 if (browser->profile() != profile())
1600 return false; 985 return false;
1601 // Never track app popup windows that do not have a trusted source (i.e. 986 // Never track app popup windows that do not have a trusted source (i.e.
1602 // popup windows spawned by an app). If this logic changes, be sure to also 987 // popup windows spawned by an app). If this logic changes, be sure to also
1603 // change SessionRestoreImpl::CreateRestoredBrowser(). 988 // change SessionRestoreImpl::CreateRestoredBrowser().
1604 if (browser->is_app() && browser->is_type_popup() && 989 if (browser->is_app() && browser->is_type_popup() &&
1605 !browser->is_trusted_source()) { 990 !browser->is_trusted_source()) {
1606 return false; 991 return false;
1607 } 992 }
1608 AppType app_type = browser->is_app() ? TYPE_APP : TYPE_NORMAL; 993 SessionServiceCommands::AppType app_type =
1609 return should_track_changes_for_browser_type(browser->type(), app_type); 994 browser->is_app() ? SessionServiceCommands::TYPE_APP :
1610 } 995 SessionServiceCommands::TYPE_NORMAL;
1611 996 return ShouldRestoreWindowOfType(WindowTypeForBrowserType(browser->type()),
1612 bool SessionService::should_track_changes_for_browser_type(Browser::Type type, 997 app_type);
1613 AppType app_type) {
1614 #if defined(OS_CHROMEOS)
1615 // Restore app popups for chromeos alone.
1616 if (type == Browser::TYPE_POPUP && app_type == TYPE_APP)
1617 return true;
1618 #endif
1619
1620 return type == Browser::TYPE_TABBED;
1621 }
1622
1623 SessionService::WindowType SessionService::WindowTypeForBrowserType(
1624 Browser::Type type) {
1625 switch (type) {
1626 case Browser::TYPE_POPUP:
1627 return TYPE_POPUP;
1628 case Browser::TYPE_TABBED:
1629 return TYPE_TABBED;
1630 default:
1631 DCHECK(false);
1632 return TYPE_TABBED;
1633 }
1634 }
1635
1636 Browser::Type SessionService::BrowserTypeForWindowType(WindowType type) {
1637 switch (type) {
1638 case TYPE_POPUP:
1639 return Browser::TYPE_POPUP;
1640 case TYPE_TABBED:
1641 default:
1642 return Browser::TYPE_TABBED;
1643 }
1644 } 998 }
1645 999
1646 void SessionService::RecordSessionUpdateHistogramData(int type, 1000 void SessionService::RecordSessionUpdateHistogramData(int type,
1647 base::TimeTicks* last_updated_time) { 1001 base::TimeTicks* last_updated_time) {
1648 if (!last_updated_time->is_null()) { 1002 if (!last_updated_time->is_null()) {
1649 base::TimeDelta delta = base::TimeTicks::Now() - *last_updated_time; 1003 base::TimeDelta delta = base::TimeTicks::Now() - *last_updated_time;
1650 // We're interested in frequent updates periods longer than 1004 // We're interested in frequent updates periods longer than
1651 // 10 minutes. 1005 // 10 minutes.
1652 bool use_long_period = false; 1006 bool use_long_period = false;
1653 if (delta >= save_delay_in_mins_) { 1007 if (delta >= save_delay_in_mins_) {
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1728 if (use_long_period) { 1082 if (use_long_period) {
1729 std::string long_name_("SessionRestore.NavEntryCommittedLongPeriod"); 1083 std::string long_name_("SessionRestore.NavEntryCommittedLongPeriod");
1730 UMA_HISTOGRAM_CUSTOM_TIMES(long_name_, 1084 UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
1731 delta, 1085 delta,
1732 save_delay_in_mins_, 1086 save_delay_in_mins_,
1733 save_delay_in_hrs_, 1087 save_delay_in_hrs_,
1734 50); 1088 50);
1735 } 1089 }
1736 } 1090 }
1737 1091
1738 void SessionService::RecordUpdatedSessionNavigationOrTab(base::TimeDelta delta, 1092 void SessionService::RecordUpdatedSaveTime(base::TimeDelta delta,
1739 bool use_long_period) { 1093 bool use_long_period) {
1740 std::string name("SessionRestore.NavOrTabUpdatePeriod"); 1094 std::string name("SessionRestore.SavePeriod");
1741 UMA_HISTOGRAM_CUSTOM_TIMES(name, 1095 UMA_HISTOGRAM_CUSTOM_TIMES(name,
1742 delta, 1096 delta,
1743 // 2500ms is the default save delay. 1097 // 2500ms is the default save delay.
1744 save_delay_in_millis_, 1098 save_delay_in_millis_,
1745 save_delay_in_mins_, 1099 save_delay_in_mins_,
1746 50); 1100 50);
1747 if (use_long_period) { 1101 if (use_long_period) {
1748 std::string long_name_("SessionRestore.NavOrTabUpdateLongPeriod"); 1102 std::string long_name_("SessionRestore.SaveLongPeriod");
1749 UMA_HISTOGRAM_CUSTOM_TIMES(long_name_, 1103 UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
1750 delta, 1104 delta,
1751 save_delay_in_mins_, 1105 save_delay_in_mins_,
1752 save_delay_in_hrs_, 1106 save_delay_in_hrs_,
1753 50); 1107 50);
1754 } 1108 }
1755 } 1109 }
1756 1110
1757 void SessionService::RecordUpdatedSaveTime(base::TimeDelta delta, 1111 void SessionService::RecordUpdatedSessionNavigationOrTab(base::TimeDelta delta,
1758 bool use_long_period) { 1112 bool use_long_period) {
1759 std::string name("SessionRestore.SavePeriod"); 1113 std::string name("SessionRestore.NavOrTabUpdatePeriod");
1760 UMA_HISTOGRAM_CUSTOM_TIMES(name, 1114 UMA_HISTOGRAM_CUSTOM_TIMES(name,
1761 delta, 1115 delta,
1762 // 2500ms is the default save delay. 1116 // 2500ms is the default save delay.
1763 save_delay_in_millis_, 1117 save_delay_in_millis_,
1764 save_delay_in_mins_, 1118 save_delay_in_mins_,
1765 50); 1119 50);
1766 if (use_long_period) { 1120 if (use_long_period) {
1767 std::string long_name_("SessionRestore.SaveLongPeriod"); 1121 std::string long_name_("SessionRestore.NavOrTabUpdateLongPeriod");
1768 UMA_HISTOGRAM_CUSTOM_TIMES(long_name_, 1122 UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
1769 delta, 1123 delta,
1770 save_delay_in_mins_, 1124 save_delay_in_mins_,
1771 save_delay_in_hrs_, 1125 save_delay_in_hrs_,
1772 50); 1126 50);
1773 } 1127 }
1774 } 1128 }
1775 1129
1776 void SessionService::TabInserted(WebContents* contents) {
1777 SessionTabHelper* session_tab_helper =
1778 SessionTabHelper::FromWebContents(contents);
1779 if (!ShouldTrackChangesToWindow(session_tab_helper->window_id()))
1780 return;
1781 SetTabWindow(session_tab_helper->window_id(),
1782 session_tab_helper->session_id());
1783 extensions::TabHelper* extensions_tab_helper =
1784 extensions::TabHelper::FromWebContents(contents);
1785 if (extensions_tab_helper &&
1786 extensions_tab_helper->extension_app()) {
1787 SetTabExtensionAppID(
1788 session_tab_helper->window_id(),
1789 session_tab_helper->session_id(),
1790 extensions_tab_helper->extension_app()->id());
1791 }
1792
1793 // Record the association between the SessionStorageNamespace and the
1794 // tab.
1795 //
1796 // TODO(ajwong): This should be processing the whole map rather than
1797 // just the default. This in particular will not work for tabs with only
1798 // isolated apps which won't have a default partition.
1799 content::SessionStorageNamespace* session_storage_namespace =
1800 contents->GetController().GetDefaultSessionStorageNamespace();
1801 ScheduleCommand(CreateSessionStorageAssociatedCommand(
1802 session_tab_helper->session_id(),
1803 session_storage_namespace->persistent_id()));
1804 session_storage_namespace->SetShouldPersist(true);
1805 }
1806
1807 void SessionService::TabClosing(WebContents* contents) {
1808 // Allow the associated sessionStorage to get deleted; it won't be needed
1809 // in the session restore.
1810 content::SessionStorageNamespace* session_storage_namespace =
1811 contents->GetController().GetDefaultSessionStorageNamespace();
1812 session_storage_namespace->SetShouldPersist(false);
1813 SessionTabHelper* session_tab_helper =
1814 SessionTabHelper::FromWebContents(contents);
1815 TabClosed(session_tab_helper->window_id(),
1816 session_tab_helper->session_id(),
1817 contents->GetClosedByUserGesture());
1818 RecordSessionUpdateHistogramData(content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
1819 &last_updated_tab_closed_time_);
1820 }
1821
1822 void SessionService::MaybeDeleteSessionOnlyData() { 1130 void SessionService::MaybeDeleteSessionOnlyData() {
1823 // Don't try anything if we're testing. The browser_process is not fully 1131 // Don't try anything if we're testing. The browser_process is not fully
1824 // created and DeleteSession will crash if we actually attempt it. 1132 // created and DeleteSession will crash if we actually attempt it.
1825 if (!profile() || profile()->AsTestingProfile()) 1133 if (!profile() || profile()->AsTestingProfile())
1826 return; 1134 return;
1827 1135
1828 // Clear session data if the last window for a profile has been closed and 1136 // Clear session data if the last window for a profile has been closed and
1829 // closing the last window would normally close Chrome, unless background mode 1137 // closing the last window would normally close Chrome, unless background mode
1830 // is active. Tests don't have a background_mode_manager. 1138 // is active. Tests don't have a background_mode_manager.
1831 if (has_open_trackable_browsers_ || 1139 if (has_open_trackable_browsers_ ||
1832 browser_defaults::kBrowserAliveWithNoWindows || 1140 browser_defaults::kBrowserAliveWithNoWindows ||
1833 g_browser_process->background_mode_manager()->IsBackgroundModeActive()) { 1141 g_browser_process->background_mode_manager()->IsBackgroundModeActive()) {
1834 return; 1142 return;
1835 } 1143 }
1836 1144
1837 // Check for any open windows for the current profile that we aren't tracking. 1145 // Check for any open windows for the current profile that we aren't tracking.
1838 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 1146 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
1839 if ((*it)->profile() == profile()) 1147 if ((*it)->profile() == profile())
1840 return; 1148 return;
1841 } 1149 }
1842 DeleteSessionOnlyData(profile()); 1150 DeleteSessionOnlyData(profile());
1843 } 1151 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698