session_service.h revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_ 6#define CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_ 7#pragma once 8 9#include <map> 10#include <string> 11 12#include "base/basictypes.h" 13#include "base/callback.h" 14#include "base/time.h" 15#include "chrome/browser/browser.h" 16#include "chrome/browser/browser_list.h" 17#include "chrome/browser/defaults.h" 18#include "chrome/browser/sessions/base_session_service.h" 19#include "chrome/browser/sessions/session_id.h" 20#include "chrome/common/notification_observer.h" 21#include "chrome/common/notification_registrar.h" 22 23class NavigationController; 24class NavigationEntry; 25class Profile; 26class SessionCommand; 27struct SessionTab; 28struct SessionWindow; 29 30// SessionService ------------------------------------------------------------ 31 32// SessionService is responsible for maintaining the state of open windows 33// and tabs so that they can be restored at a later date. The state of the 34// currently open browsers is referred to as the current session. 35// 36// SessionService supports restoring from the previous or last session. The 37// previous session typically corresponds to the last run of the browser, but 38// not always. For example, if the user has a tabbed browser and app window 39// running, closes the tabbed browser, then creates a new tabbed browser the 40// current session is made the last session and the current session reset. This 41// is done to provide the illusion that app windows run in separate processes. 42// 43// SessionService itself maintains a set of SessionCommands that allow 44// SessionService to rebuild the open state of the browser (as 45// SessionWindow, SessionTab and TabNavigation). The commands are periodically 46// flushed to SessionBackend and written to a file. Every so often 47// SessionService rebuilds the contents of the file from the open state 48// of the browser. 49class SessionService : public BaseSessionService, 50 public NotificationObserver { 51 friend class SessionServiceTestHelper; 52 public: 53 // Creates a SessionService for the specified profile. 54 explicit SessionService(Profile* profile); 55 // For testing. 56 explicit SessionService(const FilePath& save_path); 57 58 // Invoke at a point when you think session restore might occur. For example, 59 // during startup and window creation this is invoked to see if a session 60 // needs to be restored. If a session needs to be restored it is done so 61 // asynchronously and true is returned. If false is returned the session was 62 // not restored and the caller needs to create a new window. 63 bool RestoreIfNecessary(const std::vector<GURL>& urls_to_open); 64 65 // Resets the contents of the file from the current state of all open 66 // browsers whose profile matches our profile. 67 void ResetFromCurrentBrowsers(); 68 69 // Moves the current session to the last session. This is useful when a 70 // checkpoint occurs, such as when the user launches the app and no tabbed 71 // browsers are running. 72 void MoveCurrentSessionToLastSession(); 73 74 // Associates a tab with a window. 75 void SetTabWindow(const SessionID& window_id, 76 const SessionID& tab_id); 77 78 // Sets the bounds of a window. 79 void SetWindowBounds(const SessionID& window_id, 80 const gfx::Rect& bounds, 81 bool is_maximized); 82 83 // Sets the visual index of the tab in its parent window. 84 void SetTabIndexInWindow(const SessionID& window_id, 85 const SessionID& tab_id, 86 int new_index); 87 88 // Sets the pinned state of the tab. 89 void SetPinnedState(const SessionID& window_id, 90 const SessionID& tab_id, 91 bool is_pinned); 92 93 // Notification that a tab has been closed. |closed_by_user_gesture| comes 94 // from |TabContents::closed_by_user_gesture|; see it for details. 95 // 96 // Note: this is invoked from the NavigationController's destructor, which is 97 // after the actual tab has been removed. 98 void TabClosed(const SessionID& window_id, 99 const SessionID& tab_id, 100 bool closed_by_user_gesture); 101 102 // Notification the window is about to close. 103 void WindowClosing(const SessionID& window_id); 104 105 // Notification a window has finished closing. 106 void WindowClosed(const SessionID& window_id); 107 108 // Sets the type of window. In order for the contents of a window to be 109 // tracked SetWindowType must be invoked with a type we track 110 // (should_track_changes_for_browser_type returns true). 111 void SetWindowType(const SessionID& window_id, Browser::Type type); 112 113 // Invoked when the NavigationController has removed entries from the back of 114 // the list. |count| gives the number of entries in the navigation controller. 115 void TabNavigationPathPrunedFromBack(const SessionID& window_id, 116 const SessionID& tab_id, 117 int count); 118 119 // Invoked when the NavigationController has removed entries from the front of 120 // the list. |count| gives the number of entries that were removed. 121 void TabNavigationPathPrunedFromFront(const SessionID& window_id, 122 const SessionID& tab_id, 123 int count); 124 125 // Updates the navigation entry for the specified tab. 126 void UpdateTabNavigation(const SessionID& window_id, 127 const SessionID& tab_id, 128 int index, 129 const NavigationEntry& entry); 130 131 // Notification that a tab has restored its entries or a closed tab is being 132 // reused. 133 void TabRestored(NavigationController* controller, 134 bool pinned); 135 136 // Sets the index of the selected entry in the navigation controller for the 137 // specified tab. 138 void SetSelectedNavigationIndex(const SessionID& window_id, 139 const SessionID& tab_id, 140 int index); 141 142 // Sets the index of the selected tab in the specified window. 143 void SetSelectedTabInWindow(const SessionID& window_id, int index); 144 145 // Callback from GetSavedSession of GetLastSession. 146 // 147 // The contents of the supplied vector are deleted after the callback is 148 // notified. To take ownership of the vector clear it before returning. 149 // 150 // The time gives the time the session was closed. 151 typedef Callback2<Handle, std::vector<SessionWindow*>*>::Type 152 SessionCallback; 153 154 // Fetches the contents of the last session, notifying the callback when 155 // done. If the callback is supplied an empty vector of SessionWindows 156 // it means the session could not be restored. 157 // 158 // The created request does NOT directly invoke the callback, rather the 159 // callback invokes OnGotSessionCommands from which we map the 160 // SessionCommands to browser state, then notify the callback. 161 Handle GetLastSession(CancelableRequestConsumerBase* consumer, 162 SessionCallback* callback); 163 164 // Fetches the contents of the current session, notifying the callback when 165 // done. If the callback is supplied an empty vector of SessionWindows 166 // it means the session could not be restored. 167 // 168 // The created request does NOT directly invoke the callback, rather the 169 // callback invokes OnGotSessionCommands from which we map the 170 // SessionCommands to browser state, then notify the callback. 171 Handle GetCurrentSession(CancelableRequestConsumerBase* consumer, 172 SessionCallback* callback); 173 174 // Overridden from BaseSessionService because we want some UMA reporting on 175 // session update activities. 176 virtual void Save(); 177 178 private: 179 typedef std::map<SessionID::id_type, std::pair<int, int> > IdToRange; 180 typedef std::map<SessionID::id_type, SessionTab*> IdToSessionTab; 181 typedef std::map<SessionID::id_type, SessionWindow*> IdToSessionWindow; 182 183 184 virtual ~SessionService(); 185 186 // These types mirror Browser::Type, but are re-defined here because these 187 // specific enumeration _values_ are written into the session database and 188 // are needed to maintain forward compatibility. 189 enum WindowType { 190 TYPE_NORMAL = 0, 191 TYPE_POPUP = 1, 192 TYPE_APP = 2, 193 TYPE_APP_POPUP = TYPE_APP + TYPE_POPUP, 194 TYPE_DEVTOOLS = TYPE_APP + 4, 195 TYPE_APP_PANEL = TYPE_APP + 8 196 }; 197 198 void Init(); 199 200 // Implementation of RestoreIfNecessary. If |browser| is non-null and we need 201 // to restore, the tabs are added to it, otherwise a new browser is created. 202 bool RestoreIfNecessary(const std::vector<GURL>& urls_to_open, 203 Browser* browser); 204 205 virtual void Observe(NotificationType type, 206 const NotificationSource& source, 207 const NotificationDetails& details); 208 209 // Sets the application extension id of the specified tab. 210 void SetTabExtensionAppID(const SessionID& window_id, 211 const SessionID& tab_id, 212 const std::string& extension_app_id); 213 214 // Methods to create the various commands. It is up to the caller to delete 215 // the returned the SessionCommand* object. 216 SessionCommand* CreateSetSelectedTabInWindow(const SessionID& window_id, 217 int index); 218 219 SessionCommand* CreateSetTabWindowCommand(const SessionID& window_id, 220 const SessionID& tab_id); 221 222 SessionCommand* CreateSetWindowBoundsCommand(const SessionID& window_id, 223 const gfx::Rect& bounds, 224 bool is_maximized); 225 226 SessionCommand* CreateSetTabIndexInWindowCommand(const SessionID& tab_id, 227 int new_index); 228 229 SessionCommand* CreateTabClosedCommand(SessionID::id_type tab_id); 230 231 SessionCommand* CreateWindowClosedCommand(SessionID::id_type tab_id); 232 233 SessionCommand* CreateSetSelectedNavigationIndexCommand( 234 const SessionID& tab_id, 235 int index); 236 237 SessionCommand* CreateSetWindowTypeCommand(const SessionID& window_id, 238 WindowType type); 239 240 SessionCommand* CreatePinnedStateCommand(const SessionID& tab_id, 241 bool is_pinned); 242 243 // Callback from the backend for getting the commands from the previous 244 // or save file. Converts the commands in SessionWindows and notifies 245 // the real callback. 246 void OnGotSessionCommands( 247 Handle handle, 248 scoped_refptr<InternalGetCommandsRequest> request); 249 250 // Converts the commands into SessionWindows. On return any valid 251 // windows are added to valid_windows. It is up to the caller to delete 252 // the windows added to valid_windows. 253 // 254 // If ignore_recent_closes is true, any window/tab closes within in a certain 255 // time frame are ignored. 256 void RestoreSessionFromCommands(const std::vector<SessionCommand*>& commands, 257 std::vector<SessionWindow*>* valid_windows); 258 259 // Iterates through the vector updating the selected_tab_index of each 260 // SessionWindow based on the actual tabs that were restored. 261 void UpdateSelectedTabIndex(std::vector<SessionWindow*>* windows); 262 263 // Returns the window in windows with the specified id. If a window does 264 // not exist, one is created. 265 SessionWindow* GetWindow(SessionID::id_type window_id, 266 IdToSessionWindow* windows); 267 268 // Returns the tab with the specified id in tabs. If a tab does not exist, 269 // it is created. 270 SessionTab* GetTab(SessionID::id_type tab_id, 271 IdToSessionTab* tabs); 272 273 // Returns an iterator into navigations pointing to the navigation whose 274 // index matches |index|. If no navigation index matches |index|, the first 275 // navigation with an index > |index| is returned. 276 // 277 // This assumes the navigations are ordered by index in ascending order. 278 std::vector<TabNavigation>::iterator FindClosestNavigationWithIndex( 279 std::vector<TabNavigation>* navigations, 280 int index); 281 282 // Does the following: 283 // . Deletes and removes any windows with no tabs or windows with types other 284 // than tabbed_browser or browser. NOTE: constrained windows that have 285 // been dragged out are of type browser. As such, this preserves any dragged 286 // out constrained windows (aka popups that have been dragged out). 287 // . Sorts the tabs in windows with valid tabs based on the tabs 288 // visual order, and adds the valid windows to windows. 289 void SortTabsBasedOnVisualOrderAndPrune( 290 std::map<int, SessionWindow*>* windows, 291 std::vector<SessionWindow*>* valid_windows); 292 293 // Adds tabs to their parent window based on the tab's window_id. This 294 // ignores tabs with no navigations. 295 void AddTabsToWindows(std::map<int, SessionTab*>* tabs, 296 std::map<int, SessionWindow*>* windows); 297 298 // Creates tabs and windows from the specified commands. The created tabs 299 // and windows are added to |tabs| and |windows| respectively. It is up to 300 // the caller to delete the tabs and windows added to |tabs| and |windows|. 301 // 302 // This does NOT add any created SessionTabs to SessionWindow.tabs, that is 303 // done by AddTabsToWindows. 304 bool CreateTabsAndWindows(const std::vector<SessionCommand*>& data, 305 std::map<int, SessionTab*>* tabs, 306 std::map<int, SessionWindow*>* windows); 307 308 // Adds commands to commands that will recreate the state of the specified 309 // NavigationController. This adds at most kMaxNavigationCountToPersist 310 // navigations (in each direction from the current navigation index). 311 // A pair is added to tab_to_available_range indicating the range of 312 // indices that were written. 313 void BuildCommandsForTab( 314 const SessionID& window_id, 315 NavigationController* controller, 316 int index_in_window, 317 bool is_pinned, 318 std::vector<SessionCommand*>* commands, 319 IdToRange* tab_to_available_range); 320 321 // Adds commands to create the specified browser, and invokes 322 // BuildCommandsForTab for each of the tabs in the browser. This ignores 323 // any tabs not in the profile we were created with. 324 void BuildCommandsForBrowser( 325 Browser* browser, 326 std::vector<SessionCommand*>* commands, 327 IdToRange* tab_to_available_range, 328 std::set<SessionID::id_type>* windows_to_track); 329 330 // Iterates over all the known browsers invoking BuildCommandsForBrowser. 331 // This only adds browsers that should be tracked 332 // (should_track_changes_for_browser_type returns true). All browsers that 333 // are tracked are added to windows_to_track (as long as it is non-null). 334 void BuildCommandsFromBrowsers( 335 std::vector<SessionCommand*>* commands, 336 IdToRange* tab_to_available_range, 337 std::set<SessionID::id_type>* windows_to_track); 338 339 // Schedules a reset. A reset means the contents of the file are recreated 340 // from the state of the browser. 341 void ScheduleReset(); 342 343 // Searches for a pending command that can be replaced with command. 344 // If one is found, pending command is removed, command is added to 345 // the pending commands and true is returned. 346 bool ReplacePendingCommand(SessionCommand* command); 347 348 // Schedules the specified command. This method takes ownership of the 349 // command. 350 void ScheduleCommand(SessionCommand* command); 351 352 // Converts all pending tab/window closes to commands and schedules them. 353 void CommitPendingCloses(); 354 355 // Returns true if there is only one window open with a single tab that shares 356 // our profile. 357 bool IsOnlyOneTabLeft(); 358 359 // Returns true if there are open trackable browser windows whose ids do 360 // match |window_id| with our profile. A trackable window is a window from 361 // which |should_track_changes_for_browser_type| returns true. See 362 // |should_track_changes_for_browser_type| for details. 363 bool HasOpenTrackableBrowsers(const SessionID& window_id); 364 365 // Returns true if changes to tabs in the specified window should be tracked. 366 bool ShouldTrackChangesToWindow(const SessionID& window_id); 367 368 // Returns true if we track changes to the specified browser type. 369 static bool should_track_changes_for_browser_type(Browser::Type type) { 370 return type == Browser::TYPE_NORMAL || 371 (type == Browser::TYPE_POPUP && browser_defaults::kRestorePopups); 372 } 373 374 // Returns true if we should record a window close as pending. 375 // |has_open_trackable_browsers_| must be up-to-date before calling this. 376 bool should_record_close_as_pending() const { 377 // When this is called, the browser window being closed is still open, hence 378 // still in the browser list. If there is a browser window other than the 379 // one being closed but no trackable windows, then the others must be App 380 // windows or similar. In this case, we record the close as pending. 381 return !has_open_trackable_browsers_ && 382 (!browser_defaults::kBrowserAliveWithNoWindows || 383 BrowserList::size() > 1); 384 } 385 386 // Call when certain session relevant notifications 387 // (tab_closed, nav_list_pruned) occur. In addition, this is 388 // currently called when Save() is called to compare how often the 389 // session data is currently saved verses when we may want to save it. 390 // It records the data in UMA stats. 391 void RecordSessionUpdateHistogramData(NotificationType type, 392 base::TimeTicks* last_updated_time); 393 394 // Helper methods to record the histogram data 395 void RecordUpdatedTabClosed(base::TimeDelta delta, bool use_long_period); 396 void RecordUpdatedNavListPruned(base::TimeDelta delta, bool use_long_period); 397 void RecordUpdatedNavEntryCommit(base::TimeDelta delta, bool use_long_period); 398 void RecordUpdatedSaveTime(base::TimeDelta delta, bool use_long_period); 399 void RecordUpdatedSessionNavigationOrTab(base::TimeDelta delta, 400 bool use_long_period); 401 402 // Convert back/forward between the Browser and SessionService DB window 403 // types. 404 static WindowType WindowTypeForBrowserType(Browser::Type type); 405 static Browser::Type BrowserTypeForWindowType(WindowType type); 406 407 NotificationRegistrar registrar_; 408 409 // Maps from session tab id to the range of navigation entries that has 410 // been written to disk. 411 // 412 // This is only used if not all the navigation entries have been 413 // written. 414 IdToRange tab_to_available_range_; 415 416 // When the user closes the last window, where the last window is the 417 // last tabbed browser and no more tabbed browsers are open with the same 418 // profile, the window ID is added here. These IDs are only committed (which 419 // marks them as closed) if the user creates a new tabbed browser. 420 typedef std::set<SessionID::id_type> PendingWindowCloseIDs; 421 PendingWindowCloseIDs pending_window_close_ids_; 422 423 // Set of tabs that have been closed by way of the last window or last tab 424 // closing, but not yet committed. 425 typedef std::set<SessionID::id_type> PendingTabCloseIDs; 426 PendingTabCloseIDs pending_tab_close_ids_; 427 428 // When a window other than the last window (see description of 429 // pending_window_close_ids) is closed, the id is added to this set. 430 typedef std::set<SessionID::id_type> WindowClosingIDs; 431 WindowClosingIDs window_closing_ids_; 432 433 // Set of windows we're tracking changes to. This is only browsers that 434 // return true from should_track_changes_for_browser_type. 435 typedef std::set<SessionID::id_type> WindowsTracking; 436 WindowsTracking windows_tracking_; 437 438 // Are there any open trackable browsers? 439 bool has_open_trackable_browsers_; 440 441 // If true and a new tabbed browser is created and there are no opened tabbed 442 // browser (has_open_trackable_browsers_ is false), then the current session 443 // is made the previous session. See description above class for details on 444 // current/previous session. 445 bool move_on_new_browser_; 446 447 // Used for reporting frequency of session alteriing operations. 448 base::TimeTicks last_updated_tab_closed_time_; 449 base::TimeTicks last_updated_nav_list_pruned_time_; 450 base::TimeTicks last_updated_nav_entry_commit_time_; 451 base::TimeTicks last_updated_save_time_; 452 453 // Constants used in calculating histogram data. 454 const base::TimeDelta save_delay_in_millis_; 455 const base::TimeDelta save_delay_in_mins_; 456 const base::TimeDelta save_delay_in_hrs_; 457 458 DISALLOW_COPY_AND_ASSIGN(SessionService); 459}; 460 461#endif // CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_ 462