| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |